Lab-project - Data Science for Business, Università degli Studi dell'Insubria.
Ad opera di D. Gabriele
L'obiettivo del progetto è analizzare l'andamento del mercato del lavoro in Lombardia osservando le attivazioni e cessazioni di contratti durante nell'intervallo temporale intercorrente tra il 2010 e il 2021. L'idea contempla un confronto tra i settori trainanti per l'economia della regione Lombardia con particolare attenzione sul settore della ristorazione.
SOMMARIO:
import os
import math
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from os.path import exists
import requests
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
import random
from statsmodels.tsa.stattools import acf, pacf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX
from pmdarima.arima import auto_arima
from pmdarima.arima import ADFTest
from sklearn.metrics import mean_absolute_error, mean_squared_error, mean_absolute_percentage_error
from utils.metrics import evaluate
import pickle
import warnings
from math import sqrt
import matplotlib as mpl
import pmdarima as pm
import tensorflow as tf
import xgboost as xgb
from bayes_opt import BayesianOptimization
from prophet import Prophet
from matplotlib import pyplot as plt
from sklearn import linear_model, svm
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import make_scorer, mean_squared_error
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler
from statsmodels.tsa.ar_model import AR
from statsmodels.tsa.arima_model import ARIMA
from statsmodels.tsa.holtwinters import ExponentialSmoothing, SimpleExpSmoothing
from statsmodels.tsa.statespace.sarimax import SARIMAX
from tqdm import tqdm
#Importing libraries
if not exists('Rapporti_di_lavoro_attivati.csv'):
file = requests.get("https://dati.lombardia.it/api/views/qbau-cyuc/rows.csv?accessType=DOWNLOAD", allow_redirects=True)
open('Rapporti_di_lavoro_attivati.csv', 'wb').write(file.content)
if not exists('Rapporti_di_lavoro_cessati.csv'):
file = requests.get("https://dati.lombardia.it/api/views/nwz3-p6vm/rows.csv?accessType=DOWNLOAD", allow_redirects=True)
open('Rapporti_di_lavoro_cessati.csv', 'wb').write(file.content)
attivati = pd.read_csv('Rapporti_di_lavoro_attivati.csv')
cessati = pd.read_csv('Rapporti_di_lavoro_cessati.csv')
pil = pd.read_csv('PilRegioniIta.csv', encoding = 'latin')
ISPEZIONE DEI DATASET E CONSIDERAZIONI :
Analisi del dataset relativo al PIL
pil.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 105 entries, 0 to 104 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Anno 105 non-null int64 1 Regioni 105 non-null object 2 P.I.L. Milioni di Euro 105 non-null int64 dtypes: int64(2), object(1) memory usage: 2.6+ KB
pil.head()
| Anno | Regioni | P.I.L. Milioni di Euro | |
|---|---|---|---|
| 0 | 2000 | Emilia Romagna | 106154 |
| 1 | 2000 | Lazio | 138118 |
| 2 | 2000 | Lombardia | 259861 |
| 3 | 2000 | Piemonte | 99693 |
| 4 | 2000 | Veneto | 111462 |
ISPEZIONE DEI DATASET E CONSIDERAZIONI :
Analisi del dataset relativo alle attivazioni dei contratti in Lombardia
attivati.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 9579794 entries, 0 to 9579793 Data columns (total 9 columns): # Column Dtype --- ------ ----- 0 DATA object 1 GENERE object 2 ETA int64 3 SETTOREECONOMICODETTAGLIO object 4 TITOLOSTUDIO object 5 CONTRATTO object 6 MODALITALAVORO object 7 PROVINCIAIMPRESA object 8 ITALIANO object dtypes: int64(1), object(8) memory usage: 657.8+ MB
attivati.head()
ISPEZIONE DEI DATASET E CONSIDERAZIONI :
Analisi del dataset relativo alle terminazioni dei contratti in Lombardia
cessati.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 3741394 entries, 0 to 3741393 Data columns (total 9 columns): # Column Dtype --- ------ ----- 0 DATA object 1 GENERE object 2 ETA int64 3 SETTOREECONOMICODETTAGLIO object 4 TITOLOSTUDIO object 5 CONTRATTO object 6 MODALITALAVORO object 7 PROVINCIAIMPRESA object 8 ITALIANO object dtypes: int64(1), object(8) memory usage: 256.9+ MB
cessati.head()
ISPEZIONE DEI DATASET E CONSIDERAZIONI :
Conversione dei record che rappresentano le date nei dataset in 'datetime' per garantire una manipolazione
qualitativamente migliore
attivati.loc[:,'DATA'] = pd.to_datetime(attivati.loc[:,'DATA'], format="%d/%m/%Y", errors='coerce')
cessati.loc[:,'DATA'] = pd.to_datetime(cessati.loc[:,'DATA'], format="%d/%m/%Y", errors='coerce')
pil.loc[:,'Anno'] = pd.to_datetime(pil.loc[:,'Anno'], format='%Y', errors='coerce')
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Si può notare che il dataset relativo al PIL contiene informazioni su regioni al di fuori della lombardia. L'obiettivo dell'analisi si focalizza sulle osservazioni del PIL Lombardo.
pil
| Anno | Regioni | P.I.L. Milioni di Euro | |
|---|---|---|---|
| 0 | 2000-01-01 | Emilia Romagna | 106154 |
| 1 | 2000-01-01 | Lazio | 138118 |
| 2 | 2000-01-01 | Lombardia | 259861 |
| 3 | 2000-01-01 | Piemonte | 99693 |
| 4 | 2000-01-01 | Veneto | 111462 |
| ... | ... | ... | ... |
| 100 | 2020-01-01 | Lazio | 186298 |
| 101 | 2020-01-01 | Lombardia | 365515 |
| 102 | 2020-01-01 | Piemonte | 126199 |
| 103 | 2020-01-01 | Veneto | 151910 |
| 104 | 2021-01-01 | Lombardia | 391101 |
105 rows × 3 columns
prov = pil.iloc[:-1]
prov.head(10)
| Anno | Regioni | P.I.L. Milioni di Euro | |
|---|---|---|---|
| 0 | 2000-01-01 | Emilia Romagna | 106154 |
| 1 | 2000-01-01 | Lazio | 138118 |
| 2 | 2000-01-01 | Lombardia | 259861 |
| 3 | 2000-01-01 | Piemonte | 99693 |
| 4 | 2000-01-01 | Veneto | 111462 |
| 5 | 2001-01-01 | Emilia Romagna | 110741 |
| 6 | 2001-01-01 | Lazio | 146723 |
| 7 | 2001-01-01 | Lombardia | 273359 |
| 8 | 2001-01-01 | Piemonte | 104026 |
| 9 | 2001-01-01 | Veneto | 115853 |
plt.figure(figsize=(15,8))
sns.lineplot(data=prov, x='Anno',y='P.I.L. Milioni di Euro', hue='Regioni',linewidth = 4.0) #show PIL for each major region
<AxesSubplot:xlabel='Anno', ylabel='P.I.L. Milioni di Euro'>
pil.isnull().sum() #no null values check
Anno 0 Regioni 0 P.I.L. Milioni di Euro 0 dtype: int64
#remove regions that are not 'lombardia', because our study revolves around the Lombardia records
pil = pil[pil['Regioni'] == 'Lombardia']
pil = pil.loc[:, ['Anno', 'P.I.L. Milioni di Euro',]] #we remove the Regioni attribute because we only have Lombardia wich is a obvious information
pil
| Anno | P.I.L. Milioni di Euro | |
|---|---|---|
| 2 | 2000-01-01 | 259861 |
| 7 | 2001-01-01 | 273359 |
| 12 | 2002-01-01 | 285312 |
| 17 | 2003-01-01 | 294774 |
| 22 | 2004-01-01 | 304987 |
| 27 | 2005-01-01 | 313488 |
| 32 | 2006-01-01 | 323238 |
| 37 | 2007-01-01 | 336926 |
| 42 | 2008-01-01 | 349924 |
| 47 | 2009-01-01 | 334011 |
| 52 | 2010-01-01 | 349558 |
| 57 | 2011-01-01 | 357748 |
| 62 | 2012-01-01 | 351390 |
| 67 | 2013-01-01 | 348117 |
| 72 | 2014-01-01 | 355347 |
| 77 | 2015-01-01 | 362330 |
| 82 | 2016-01-01 | 373038 |
| 87 | 2017-01-01 | 383033 |
| 91 | 2018-01-01 | 393500 |
| 96 | 2019-01-01 | 397507 |
| 101 | 2020-01-01 | 365515 |
| 104 | 2021-01-01 | 391101 |
pil.info() #correctly converted to dateTime
<class 'pandas.core.frame.DataFrame'> Int64Index: 22 entries, 2 to 104 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Anno 22 non-null datetime64[ns] 1 P.I.L. Milioni di Euro 22 non-null int64 dtypes: datetime64[ns](1), int64(1) memory usage: 528.0 bytes
pil.index = pil.Anno
pilgg = pil.copy()
pilgg.index = pd.DatetimeIndex(pilgg['Anno']).year #year as index to perform operations on dates and ts analyisi
pilgg2 = pilgg.copy()
pilgg2.drop(columns='Anno', inplace = True)
pilgg2
| P.I.L. Milioni di Euro | |
|---|---|
| Anno | |
| 2000 | 259861 |
| 2001 | 273359 |
| 2002 | 285312 |
| 2003 | 294774 |
| 2004 | 304987 |
| 2005 | 313488 |
| 2006 | 323238 |
| 2007 | 336926 |
| 2008 | 349924 |
| 2009 | 334011 |
| 2010 | 349558 |
| 2011 | 357748 |
| 2012 | 351390 |
| 2013 | 348117 |
| 2014 | 355347 |
| 2015 | 362330 |
| 2016 | 373038 |
| 2017 | 383033 |
| 2018 | 393500 |
| 2019 | 397507 |
| 2020 | 365515 |
| 2021 | 391101 |
kwsne = dict(marker='o')
pilgg2.plot(figsize =(15,6),**kwsne, linewidth = 3.0)
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Analisi e null value inspection dei dataset maggiori: contratti attivati in Lombardia
attivati
| DATA | GENERE | ETA | SETTOREECONOMICODETTAGLIO | TITOLOSTUDIO | CONTRATTO | MODALITALAVORO | PROVINCIAIMPRESA | ITALIANO | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-05-09 | F | 60 | Attività di famiglie e convivenze come datori ... | NESSUN TITOLO DI STUDIO | LAVORO DOMESTICO | TEMPO PIENO | BERGAMO | UCRAINA |
| 1 | 2019-07-12 | M | 43 | Gestioni di funicolari, ski-lift e seggiovie s... | LICENZA MEDIA | LAVORO A TEMPO DETERMINATO | TEMPO PIENO | BERGAMO | ITALIA |
| 2 | 2013-06-05 | F | 20 | Fabbricazione di altre apparecchiature elettri... | LICENZA MEDIA | APPRENDISTATO PROFESSIONALIZZANTE O CONTRATTO ... | TEMPO PIENO | BERGAMO | ITALIA |
| 3 | 2010-03-12 | F | 28 | Alberghi | DIPLOMA DI ISTRUZIONE SECONDARIA SUPERIORE CH... | LAVORO INTERMITTENTE A TEMPO DETERMINATO | NON DEFINITO | BERGAMO | ITALIA |
| 4 | 2021-04-06 | F | 49 | Rifugi di montagna | LICENZA MEDIA | LAVORO INTERMITTENTE | NON DEFINITO | BERGAMO | ITALIA |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 9579789 | 2020-03-01 | M | 52 | Lavori di meccanica generale | LICENZA MEDIA | LAVORO A TEMPO DETERMINATO | TEMPO PIENO | BERGAMO | ITALIA |
| 9579790 | 2010-09-06 | M | 61 | Lavori di meccanica generale | NESSUN TITOLO DI STUDIO | LAVORO A TEMPO INDETERMINATO | TEMPO PIENO | BERGAMO | ALBANIA |
| 9579791 | 2021-11-06 | M | 37 | Fabbricazione di parti ed accessori per bicicl... | NESSUN TITOLO DI STUDIO | LAVORO A TEMPO DETERMINATO | TEMPO PIENO | BERGAMO | SENEGAL |
| 9579792 | 2010-02-02 | M | 35 | Fabbricazione di parti ed accessori per bicicl... | LICENZA MEDIA | LAVORO INTERINALE (O A SCOPO DI SOMMINISTRAZIO... | TEMPO PIENO | BERGAMO | SENEGAL |
| 9579793 | 2012-07-05 | F | 39 | Commercio all'ingrosso di abbigliamento e acce... | LICENZA MEDIA | LAVORO INTERINALE (O A SCOPO DI SOMMINISTRAZIO... | NaN | BERGAMO | ITALIA |
9579794 rows × 9 columns
copia = attivati.copy() #copy for activation dataset
copia.isna().sum()[copia.isna().sum()>0].plot(kind='bar') #null values insection for activated contracts
<AxesSubplot:>
len(copia)
9579794
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Analisi e null value inspection dei dataset maggiori: contratti cessati in Lombardia
aipoc= cessati.copy() #copy for terminated dataset
aipoc
aipoc.isna().sum()[aipoc.isna().sum()>0].plot(kind='bar') #null values inspection for terminated contracts
<AxesSubplot:>
len(aipoc)
3741394
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
I dataset presentano delle inconsistenze; le quantità maggiori di null values si contano negli attributi 'titolo di studio', 'modalità di lavoro' e 'settore economicodettaglio'.
La nostra analisi tuttavia ignora i dati relativi alla modalità di lavoro, al titolo di studio, alla nazionalità e alla provincia, pertanto possiamo eliminare le colonne relative ai suddetti dati.
copia.drop(columns = ['MODALITALAVORO', 'TITOLOSTUDIO', 'ITALIANO', 'PROVINCIAIMPRESA'], inplace = True)
aipoc.drop(columns=['MODALITALAVORO', 'TITOLOSTUDIO', 'ITALIANO', 'PROVINCIAIMPRESA'], inplace = True)
copia.isnull().sum()
DATA 0 GENERE 0 ETA 0 SETTOREECONOMICODETTAGLIO 2888 CONTRATTO 0 dtype: int64
aipoc.isnull().sum()
DATA 1 GENERE 0 ETA 0 SETTOREECONOMICODETTAGLIO 1019 CONTRATTO 0 dtype: int64
Possiamo notare che in entrambi i casi 'SETTOREECONOMICODETTAGLIO' ha una quantità discreta di valori nulli, quindi dobbiamo occuparcene senza modificare troppo le statistiche. Reminder: abbiamo bisogno di dati relativi al 'SETTOREECONOMICODETTAGLIO'.
Si noti che i valori nulli di 'SETTOREECONOMICODETTAGLIO' sono 2888/9579794, pari a circa lo 0,03% del dataset per i contratti attivati, e 1019/3741394, pari a circa lo 0,027% del dataset.
Possiamo rimuoverli senza bisogno di interpolazioni.
copia.dropna(inplace=True)
aipoc.dropna(inplace=True)
copia.isnull().sum() #null value check after cleaning the activated contracts dataset
DATA 0 GENERE 0 ETA 0 SETTOREECONOMICODETTAGLIO 0 CONTRATTO 0 dtype: int64
aipoc.isnull().sum() #null value check after cleaning the terminated contracts dataset
DATA 0 GENERE 0 ETA 0 SETTOREECONOMICODETTAGLIO 0 CONTRATTO 0 dtype: int64
copia.index = copia['DATA']
aipoc.index = aipoc['DATA']
#creation of a new column for the major datasets with copy of date
Creazione dell'attributo 'STATO' per l'identificazione di contratti attivati o cessati in vista del merging dei dataset
copiafilt = copia.copy()
copiafilt['STATO'] = 1
copiafilt
aipocfilt = aipoc.copy()
aipocfilt['STATO'] = 0
aipocfilt
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Merge dei dataset maggiori
dFrames = [copiafilt,aipocfilt]
unifDf = pd.concat(dFrames)
#merge of the two dataset in one; the datasets have the same attributes so it will be easier to do filtering and cleaning operations once they have been merged together
unifDf
| DATA | GENERE | ETA | SETTOREECONOMICODETTAGLIO | CONTRATTO | STATO | |
|---|---|---|---|---|---|---|
| DATA | ||||||
| 2020-05-09 | 2020-05-09 | F | 60 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO | 1 |
| 2019-07-12 | 2019-07-12 | M | 43 | Gestioni di funicolari, ski-lift e seggiovie s... | LAVORO A TEMPO DETERMINATO | 1 |
| 2013-06-05 | 2013-06-05 | F | 20 | Fabbricazione di altre apparecchiature elettri... | APPRENDISTATO PROFESSIONALIZZANTE O CONTRATTO ... | 1 |
| 2010-03-12 | 2010-03-12 | F | 28 | Alberghi | LAVORO INTERMITTENTE A TEMPO DETERMINATO | 1 |
| 2021-04-06 | 2021-04-06 | F | 49 | Rifugi di montagna | LAVORO INTERMITTENTE | 1 |
| ... | ... | ... | ... | ... | ... | ... |
| 2018-11-05 | 2018-11-05 | M | 19 | Fabbricazione di altri elementi in legno e di ... | LAVORO A TEMPO DETERMINATO | 0 |
| 2017-04-09 | 2017-04-09 | M | 67 | Altra istruzione secondaria di secondo grado d... | LAVORO A TEMPO INDETERMINATO | 0 |
| 2015-05-08 | 2015-05-08 | M | 59 | Costruzione di edifici residenziali e non resi... | LAVORO A TEMPO INDETERMINATO | 0 |
| 2016-10-10 | 2016-10-10 | M | 26 | Installazione di altre macchine ed apparecchia... | LAVORO A TEMPO INDETERMINATO | 0 |
| 2018-10-09 | 2018-10-09 | M | 45 | Fabbricazione di strutture metalliche e parti ... | LAVORO A TEMPO INDETERMINATO | 0 |
13317280 rows × 6 columns
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Trasformazione ed encoding delle variabili
unifDf.loc[(unifDf['GENERE'] == 'M'), 'GENERE'] = 1
unifDf.loc[(unifDf['GENERE'] == 'F'), 'GENERE'] = 0
copiaEpic = unifDf
copiaEpic
#genere to 1 for males and 0 for females
copiaEpicFilt = copiaEpic.copy()
copiaEpicFilt['Mese'] = copiaEpicFilt['DATA'].dt.month
copiaEpicFilt['Anno'] = copiaEpicFilt['DATA'].dt.year
#estrapolating year and month from the dates
copiaEpicFilt
| DATA | GENERE | ETA | SETTOREECONOMICODETTAGLIO | CONTRATTO | STATO | Mese | Anno | |
|---|---|---|---|---|---|---|---|---|
| DATA | ||||||||
| 2020-05-09 | 2020-05-09 | 0 | 60 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO | 1 | 5 | 2020 |
| 2019-07-12 | 2019-07-12 | 1 | 43 | Gestioni di funicolari, ski-lift e seggiovie s... | LAVORO A TEMPO DETERMINATO | 1 | 7 | 2019 |
| 2013-06-05 | 2013-06-05 | 0 | 20 | Fabbricazione di altre apparecchiature elettri... | APPRENDISTATO PROFESSIONALIZZANTE O CONTRATTO ... | 1 | 6 | 2013 |
| 2010-03-12 | 2010-03-12 | 0 | 28 | Alberghi | LAVORO INTERMITTENTE A TEMPO DETERMINATO | 1 | 3 | 2010 |
| 2021-04-06 | 2021-04-06 | 0 | 49 | Rifugi di montagna | LAVORO INTERMITTENTE | 1 | 4 | 2021 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2018-11-05 | 2018-11-05 | 1 | 19 | Fabbricazione di altri elementi in legno e di ... | LAVORO A TEMPO DETERMINATO | 0 | 11 | 2018 |
| 2017-04-09 | 2017-04-09 | 1 | 67 | Altra istruzione secondaria di secondo grado d... | LAVORO A TEMPO INDETERMINATO | 0 | 4 | 2017 |
| 2015-05-08 | 2015-05-08 | 1 | 59 | Costruzione di edifici residenziali e non resi... | LAVORO A TEMPO INDETERMINATO | 0 | 5 | 2015 |
| 2016-10-10 | 2016-10-10 | 1 | 26 | Installazione di altre macchine ed apparecchia... | LAVORO A TEMPO INDETERMINATO | 0 | 10 | 2016 |
| 2018-10-09 | 2018-10-09 | 1 | 45 | Fabbricazione di strutture metalliche e parti ... | LAVORO A TEMPO INDETERMINATO | 0 | 10 | 2018 |
13317280 rows × 8 columns
mergedData = pd.merge(copiaEpicFilt, pilgg2, how = 'inner', on = 'Anno')
#merging dataframes with pil dataset
mergedData
| DATA | GENERE | ETA | SETTOREECONOMICODETTAGLIO | CONTRATTO | STATO | Mese | Anno | P.I.L. Milioni di Euro | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-05-09 | 0 | 60 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO | 1 | 5 | 2020 | 365515 |
| 1 | 2020-03-07 | 1 | 37 | Costruzione di strade, autostrade e piste aero... | LAVORO A TEMPO DETERMINATO | 1 | 3 | 2020 | 365515 |
| 2 | 2020-01-06 | 1 | 28 | Costruzione di strade, autostrade e piste aero... | LAVORO A TEMPO DETERMINATO | 1 | 1 | 2020 | 365515 |
| 3 | 2020-06-03 | 1 | 55 | Bar e altri esercizi simili senza cucina | LAVORO A TEMPO DETERMINATO | 1 | 6 | 2020 | 365515 |
| 4 | 2020-05-08 | 0 | 28 | Bar e altri esercizi simili senza cucina | LAVORO INTERMITTENTE | 1 | 5 | 2020 | 365515 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 13317240 | 2000-02-03 | 1 | 42 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 2 | 2000 | 259861 |
| 13317241 | 2000-09-06 | 0 | 31 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 9 | 2000 | 259861 |
| 13317242 | 2000-03-01 | 0 | 46 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 3 | 2000 | 259861 |
| 13317243 | 2000-01-07 | 1 | 38 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 1 | 2000 | 259861 |
| 13317244 | 2000-11-09 | 0 | 58 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 11 | 2000 | 259861 |
13317245 rows × 9 columns
mergedDataCopy = mergedData.copy()
mergedDataCopy.sort_values('DATA', inplace=True)
mergedDataCopy.index = mergedDataCopy['DATA']
mergedDataCopy.rename(columns = {'DATA':'DATE','SETTOREECONOMICODETTAGLIO' : 'SETTORE',
'Mese' : 'MESE', 'Anno' : 'ANNO', 'P.I.L. Milioni di Euro' : 'PIL MLN EUR ANNUO' }, inplace=True)
transField = LabelEncoder().fit_transform(mergedDataCopy.SETTORE)
transCon = LabelEncoder().fit_transform(mergedDataCopy.CONTRATTO)
mergedDataCopy['SETT_ID'] = transField
mergedDataCopy['CONTR_N'] = transCon
mergedDataCopy.head()
| DATE | GENERE | ETA | SETTORE | CONTRATTO | STATO | MESE | ANNO | PIL MLN EUR ANNUO | SETT_ID | CONTR_N | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| DATA | |||||||||||
| 2000-01-07 | 2000-01-07 | 1 | 38 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 1 | 2000 | 259861 | 188 | 34 |
| 2000-02-03 | 2000-02-03 | 1 | 42 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 2 | 2000 | 259861 | 188 | 34 |
| 2000-03-01 | 2000-03-01 | 0 | 46 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 3 | 2000 | 259861 | 188 | 34 |
| 2000-09-06 | 2000-09-06 | 0 | 31 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 9 | 2000 | 259861 | 188 | 34 |
| 2000-11-09 | 2000-11-09 | 0 | 58 | Attività di famiglie e convivenze come datori ... | LAVORO DOMESTICO A TEMPO INDETERMINATO | 0 | 11 | 2000 | 259861 | 188 | 34 |
columns_titles = ['CONTRATTO','CONTR_N', 'SETTORE', 'SETT_ID' , 'STATO',
'ETA', 'GENERE', 'DATE', 'MESE', 'ANNO', 'PIL MLN EUR ANNUO']
mergedDataCopy = mergedDataCopy.reindex(columns=columns_titles)
mergedDataCopy
#reordering the dataset
dfOrdinato = mergedDataCopy.copy()
dfOrdinato
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Controllo e pulizia dei dati inconsistenti ed outliers
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(20,8))
sns.boxplot(x = dfOrdinato['ETA'].loc[dfOrdinato['STATO'] == 1], ax=ax1)
sns.boxplot(x = dfOrdinato['ETA'].loc[dfOrdinato['STATO'] == 0], ax=ax2)
plt.show()
#lets clean age. We have ages that are not particoularly suitable for our analysis
etaDaDropp = dfOrdinato[(dfOrdinato.ETA >= 18) & (dfOrdinato.ETA <= 67) &
(dfOrdinato['DATE'].dt.year>2009 ) & (dfOrdinato['DATE'].dt.year<2022)]
#range di interesse di età per un contratto lavorativo che possa essere rilevante nella media legale
#range di interesse per anni in cui la digitalizzazione e i social hanno incominciato a segnare un'evoluzione nel mondo del lavoro
etaDaDropp
| CONTRATTO | CONTR_N | SETTORE | SETT_ID | STATO | ETA | GENERE | DATE | MESE | ANNO | PIL MLN EUR ANNUO | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| DATA | |||||||||||
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Cura e manutenzione del paesaggio (inclusi par... | 502 | 1 | 44 | 0 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A DOMICILIO A TEMPO INDETERMINATO | 23 | Preparazione e filatura di fibre tessili | 965 | 0 | 60 | 0 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Attività che seguono la raccolta | 134 | 1 | 33 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO INDETERMINATO | 27 | Altri servizi di supporto alle imprese nca | 123 | 1 | 28 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Attività che seguono la raccolta | 134 | 1 | 54 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Servizi logistici relativi alla distribuzione ... | 1170 | 0 | 39 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | APPRENDISTATO PROFESSIONALIZZANTE O CONTRATTO ... | 8 | Altre attività di consulenza imprenditoriale e... | 88 | 1 | 29 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO DETERMINATO | 25 | Servizi logistici relativi alla distribuzione ... | 1170 | 1 | 24 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Commercio all'ingrosso di altri materiali da c... | 374 | 1 | 39 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO DETERMINATO | 25 | Attività di produzione cinematografica, di vid... | 207 | 1 | 47 | 0 | 2021-12-09 | 12 | 2021 | 391101 |
12606817 rows × 11 columns
cleanData = etaDaDropp.copy()
dfOrdAtt = cleanData.loc[cleanData['STATO'] == 1]
dfOrdCess = cleanData.loc[cleanData['STATO'] == 0]
#grouping activated and terminated contracts to perform analysis
dfOrdAtt
| CONTRATTO | CONTR_N | SETTORE | SETT_ID | STATO | ETA | GENERE | DATE | MESE | ANNO | PIL MLN EUR ANNUO | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| DATA | |||||||||||
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Cura e manutenzione del paesaggio (inclusi par... | 502 | 1 | 44 | 0 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Attività che seguono la raccolta | 134 | 1 | 33 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO INDETERMINATO | 27 | Altri servizi di supporto alle imprese nca | 123 | 1 | 28 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Attività che seguono la raccolta | 134 | 1 | 54 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO INDETERMINATO | 27 | Altri servizi di supporto alle imprese nca | 123 | 1 | 34 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Attività non specializzate di lavori edili (mu... | 224 | 1 | 38 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | APPRENDISTATO PROFESSIONALIZZANTE O CONTRATTO ... | 8 | Altre attività di consulenza imprenditoriale e... | 88 | 1 | 29 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO DETERMINATO | 25 | Servizi logistici relativi alla distribuzione ... | 1170 | 1 | 24 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Commercio all'ingrosso di altri materiali da c... | 374 | 1 | 39 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO DETERMINATO | 25 | Attività di produzione cinematografica, di vid... | 207 | 1 | 47 | 0 | 2021-12-09 | 12 | 2021 | 391101 |
9083633 rows × 11 columns
dfOrdCess
| CONTRATTO | CONTR_N | SETTORE | SETT_ID | STATO | ETA | GENERE | DATE | MESE | ANNO | PIL MLN EUR ANNUO | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| DATA | |||||||||||
| 2010-01-01 | LAVORO A DOMICILIO A TEMPO INDETERMINATO | 23 | Preparazione e filatura di fibre tessili | 965 | 0 | 60 | 0 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Raccolta e depurazione delle acque di scarico | 1046 | 0 | 36 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO INDETERMINATO | 27 | Bar e altri esercizi simili senza cucina | 235 | 0 | 36 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO DETERMINATO | 25 | Trasporto di merci su strada | 1203 | 0 | 31 | 1 | 2010-01-01 | 1 | 2010 | 349558 |
| 2010-01-01 | LAVORO A TEMPO INDETERMINATO | 27 | Agenti di assicurazioni | 5 | 0 | 52 | 0 | 2010-01-01 | 1 | 2010 | 349558 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2021-12-09 | LAVORO DOMESTICO | 32 | Attività di famiglie e convivenze come datori ... | 188 | 0 | 45 | 0 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Servizi logistici relativi alla distribuzione ... | 1170 | 0 | 46 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO DETERMINATO | 25 | Coltivazione di ortaggi(inclusi i meloni) in f... | 262 | 0 | 52 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Servizi logistici relativi alla distribuzione ... | 1170 | 0 | 25 | 0 | 2021-12-09 | 12 | 2021 | 391101 |
| 2021-12-09 | LAVORO A TEMPO INDETERMINATO | 27 | Servizi logistici relativi alla distribuzione ... | 1170 | 0 | 39 | 1 | 2021-12-09 | 12 | 2021 | 391101 |
3523184 rows × 11 columns
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(20,8))
sns.boxplot(x = dfOrdAtt['ETA'], ax=ax1)
sns.boxplot(x = dfOrdCess['ETA'], ax=ax2)
plt.show()
dfOrdAtt.isnull().sum()
CONTRATTO 0 CONTR_N 0 SETTORE 0 SETT_ID 0 STATO 0 ETA 0 GENERE 0 DATE 0 MESE 0 ANNO 0 PIL MLN EUR ANNUO 0 dtype: int64
dfOrdCess.isnull().sum()
CONTRATTO 0 CONTR_N 0 SETTORE 0 SETT_ID 0 STATO 0 ETA 0 GENERE 0 DATE 0 MESE 0 ANNO 0 PIL MLN EUR ANNUO 0 dtype: int64
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Analisi dei settori più importanti. Preparazione dei dati per costruire un dataset utile
dfOrdAtt.value_counts('SETTORE') #settori più importanti per attivazioni
SETTORE
Alberghi 437403
Ristorazione con somministrazione 424929
Attività di produzione cinematografica, di video e di programmi televisivi 355267
Attività di famiglie e convivenze come datori di lavoro per personale domestico 326150
Altri servizi di supporto alle imprese nca 281581
...
Agenti e rappresentanti di giocattoli 1
Attività delle guide alpine 1
Coltivazione di fiori in colture protette fuori suolo 1
Allevamento di cammelli e camelidi 1
Gestione di stazioni per autobus 1
Length: 1224, dtype: int64
aa = dfOrdAtt.groupby('SETTORE').count().sort_values(by = 'CONTRATTO', ascending=False)
aa
perAtt = aa.head(10)
dfOrdCess.value_counts('SETTORE') #settori più importanti per cessazioni
SETTORE
Attività di famiglie e convivenze come datori di lavoro per personale domestico 258683
Ristorazione con somministrazione 202637
Costruzione di edifici residenziali e non residenziali 171079
Pulizia generale (non specializzata) di edifici 145277
Altri servizi di supporto alle imprese nca 143166
...
Gestione di stazioni per autobus 1
Fabbricazione di altri prodotti petroliferi raffinati 1
Commercio all'ingrosso di tabacco grezzo 1
Agenti e rappresentanti di pellicce 1
Commercio al dettaglio di spaghi, cordami, tele e sacchi di juta e prodotti per l'imballaggio (esclusi quelli in carta e cartone) 1
Length: 1205, dtype: int64
ab = dfOrdCess.groupby('SETTORE').count().sort_values(by = 'CONTRATTO', ascending=False)
ab
perCess = ab.head(10)
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Costruzione dei dataset per la top 10 attivazioni per contratti attivati
perAtt = perAtt.loc[:, ['STATO',]]
perAtt['CESSAZIONI'] = ab['STATO'].loc[ab.index.isin(perAtt.index.tolist())]
perAtt.rename(columns = {'STATO' : 'ATTIVAZIONI'}, inplace = True)
perAtt
| ATTIVAZIONI | CESSAZIONI | |
|---|---|---|
| SETTORE | ||
| Alberghi | 437403 | 61989 |
| Ristorazione con somministrazione | 424929 | 202637 |
| Attività di produzione cinematografica, di video e di programmi televisivi | 355267 | 7561 |
| Attività di famiglie e convivenze come datori di lavoro per personale domestico | 326150 | 258683 |
| Altri servizi di supporto alle imprese nca | 281581 | 143166 |
| Pulizia generale (non specializzata) di edifici | 252967 | 145277 |
| Istruzione secondaria di primo grado: scuole medie | 249435 | 21910 |
| Costruzione di edifici residenziali e non residenziali | 223083 | 171079 |
| Commercio al dettaglio di confezioni per adulti | 157768 | 32198 |
| Istruzione primaria: scuole elementari | 156582 | 12745 |
PULIZIA DEI DATASET, CORREZIONE DEI DATI E TRASFORMAZIONE:
Costruzione dei dataset per la top 10 attivazioni per contratti cessati
perCess = perCess.loc[:, ['STATO',]]
perCess['ATTIVAZIONI'] = aa['STATO'].loc[aa.index.isin(perCess.index.tolist())]
perCess.rename(columns = {'STATO' : 'CESSAZIONI'}, inplace = True)
perCess
| CESSAZIONI | ATTIVAZIONI | |
|---|---|---|
| SETTORE | ||
| Attività di famiglie e convivenze come datori di lavoro per personale domestico | 258683 | 326150 |
| Ristorazione con somministrazione | 202637 | 424929 |
| Costruzione di edifici residenziali e non residenziali | 171079 | 223083 |
| Pulizia generale (non specializzata) di edifici | 145277 | 252967 |
| Altri servizi di supporto alle imprese nca | 143166 | 281581 |
| Trasporto di merci su strada | 86094 | 126545 |
| Bar e altri esercizi simili senza cucina | 85297 | 149918 |
| Servizi logistici relativi alla distribuzione delle merci | 69199 | 125653 |
| Alberghi | 61989 | 437403 |
| Movimento merci relativo ad altri trasporti terrestri | 56825 | 75983 |
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Visualizzazione e plot dei 10 settori più importanti per attivazioni. Il settore alberghiero e quello della
ristorazione dominano le statistiche.
ax = perAtt.plot.bar(width = 0.6, figsize = (15,6))
#plot attivazioni più rilevanti
#plt.ticklabel_format(style='plain')
counts=dfOrdAtt.loc[:, ['SETTORE']].value_counts()
counts=counts.head(10)
pltfigsize=(20,15)
plt.figure(figsize=pltfigsize)
plt.ticklabel_format(style='plain') #Importante lasciare qui questo comando
plt.barh(y=[i[0] for i in counts.index], width=counts.values, color='green')
plt.title('Numero di contratti attivati per settore')
plt.xlabel('CONTRATTI ATTIVATI')
plt.ylabel('SETTORE')
Text(0, 0.5, 'SETTORE')
#visualizing percentage of activated contracts for genre
# Creating dataset
geners = dfOrdAtt.GENERE.value_counts()
data = geners.values
indx = geners.index
# Creating explode data
explode = (0.1, 0.0)
# Creating color parameters
colors = ( "blue", "red")
# Wedge properties
wp = { 'linewidth' : 1, 'edgecolor' : "black" }
# Creating autocpt arguments
def func(pct, allvalues):
absolute = int(pct / 100.*np.sum(allvalues))
return "{:.1f}%\n({:d})".format(pct, absolute)
# Creating plot
fig, ax = plt.subplots(figsize =(10, 7))
wedges, texts, autotexts = ax.pie(data,
autopct = lambda pct: func(pct, data),
explode = explode,
labels = indx,
shadow = True,
colors = colors,
startangle = 90,
wedgeprops = wp,
textprops = dict(color ="white"))
# Adding legend
ax.legend(wedges, indx,
title ="Genere: 1 = Male, 0 = Female",
loc ="center left",
bbox_to_anchor =(1, 0, 0.5, 1))
plt.setp(autotexts, size = 8, weight ="bold")
ax.set_title("Pie chart genere attivazioni")
# show plot
plt.show()
value_count_modalita = dfOrdAtt.loc[:, ['ANNO']].value_counts()
plt.ticklabel_format(style='plain')
abscissa_axis=value_count_modalita.index
ordinate_axis=value_count_modalita.values
ax=value_count_modalita.plot.bar(x=abscissa_axis,y=ordinate_axis,color='orange', figsize = (18,9))
plt.title('Numero di contratti attivati per Anno')
plt.xlabel('ANNI DI RIFERIMENTO')
plt.ylabel('NUMERO ATTIVAZIONI')
Text(0, 0.5, 'NUMERO ATTIVAZIONI')
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Visualizzazione e plot dei 10 settori più importanti per cessazioni.
Il settore del personale domestico e quello della ristorazione presentano una quantità importante di cessazioni.
Il settore della ristorazione ha un notevole turnover essendo in seconda posizione per frequenza di attivazioni
ma anche di cessazioni.
ax = perCess.plot.bar(width = 0.6, figsize = (15,6), color = ['red','green'])
#plot cessazioni più rilevanti
#plt.ticklabel_format(style='plain')
counts=dfOrdCess.loc[:, ['SETTORE']].value_counts()
counts=counts.head(10)
pltfigsize=(20,15)
plt.figure(figsize=pltfigsize)
plt.ticklabel_format(style='plain') #Importante lasciare qui questo comando
plt.barh(y=[i[0] for i in counts.index], width=counts.values, color='red')
plt.title('Numero di contratti cessati per settore')
plt.xlabel('CONTRATTI CESSATI')
plt.ylabel('SETTORE')
Text(0, 0.5, 'SETTORE')
#visualizing percentage of activated contracts for genre
# Creating dataset
geners = dfOrdCess.GENERE.value_counts()
data = geners.values
indx = geners.index
# Creating explode data
explode = (0.1, 0.0)
# Creating color parameters
colors = ( "orange", "pink")
# Wedge properties
wp = { 'linewidth' : 1, 'edgecolor' : "black" }
# Creating autocpt arguments
def func(pct, allvalues):
absolute = int(pct / 100.*np.sum(allvalues))
return "{:.1f}%\n({:d})".format(pct, absolute)
# Creating plot
fig, ax = plt.subplots(figsize =(10, 7))
wedges, texts, autotexts = ax.pie(data,
autopct = lambda pct: func(pct, data),
explode = explode,
labels = indx,
shadow = True,
colors = colors,
startangle = 90,
wedgeprops = wp,
textprops = dict(color ="black"))
# Adding legend
ax.legend(wedges, indx,
title ="Genere: 1 = Male, 0 = Female",
loc ="center left",
bbox_to_anchor =(1, 0, 0.5, 1))
plt.setp(autotexts, size = 8, weight ="bold")
ax.set_title("Pie chart genere cessazioni")
# show plot
plt.show()
value_count_modalita = dfOrdCess.loc[:, ['ANNO']].value_counts()
plt.ticklabel_format(style='plain')
abscissa_axis=value_count_modalita.index
ordinate_axis=value_count_modalita.values
ax=value_count_modalita.plot.bar(x=abscissa_axis,y=ordinate_axis,color='red', figsize = (18,9))
plt.title('Numero di contratti cessati per anno')
plt.xlabel('ANNI DI RIFERIMENTO')
plt.ylabel('NUMERO CESSAZIONI')
Text(0, 0.5, 'NUMERO CESSAZIONI')
sns.set(rc={"figure.figsize":(25,15)})
plt.subplot(3,3,2)
sns.histplot(dfOrdAtt.DATE,label="DATA",stat="density",bins=10,kde=True, color="orange").set_title("Distrubuzione contratti attivati negli anni", color = 'green')
plt.subplot(3,3,3)
sns.histplot(dfOrdCess.DATE,label="DATA",stat="density",bins=10,kde=True, color="orange").set_title("Distribuzione contratti cessati negli anni", color = 'red')
Text(0.5, 1.0, 'Distribuzione contratti cessati negli anni')
attivHead = dfOrdAtt.loc[dfOrdAtt['SETTORE'].isin(perAtt.index)]
cessHead = dfOrdCess.loc[dfOrdCess['SETTORE'].isin(perCess.index)]
cessHead['SETTORE'].value_counts()
Attività di famiglie e convivenze come datori di lavoro per personale domestico 258683 Ristorazione con somministrazione 202637 Costruzione di edifici residenziali e non residenziali 171079 Pulizia generale (non specializzata) di edifici 145277 Altri servizi di supporto alle imprese nca 143166 Trasporto di merci su strada 86094 Bar e altri esercizi simili senza cucina 85297 Servizi logistici relativi alla distribuzione delle merci 69199 Alberghi 61989 Movimento merci relativo ad altri trasporti terrestri 56825 Name: SETTORE, dtype: int64
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Correlazione tra i 10 settori più importanti per attivazioni.
La matrice di correlazione evidenzia la correlazione tra i settori di attivazione e tra settori e PIL
mostA = aa.head(10).index.tolist()
mostA
mostC = ab.head(10).index.tolist()
mostC
li = mostA
li2 = mostC
dfAttivatiMost = pd.DataFrame(columns=[li]) #da rinominare dfAttivatiMost
for k in li:
a = dfOrdAtt.loc[(dfOrdAtt['SETTORE'] == k)].ANNO.value_counts()
dfAttivatiMost[k] = a
dfAttivatiMost.sort_index(inplace= True)
dfAttivatiMost
| Alberghi | Ristorazione con somministrazione | Attività di produzione cinematografica, di video e di programmi televisivi | Attività di famiglie e convivenze come datori di lavoro per personale domestico | Altri servizi di supporto alle imprese nca | Pulizia generale (non specializzata) di edifici | Istruzione secondaria di primo grado: scuole medie | Costruzione di edifici residenziali e non residenziali | Commercio al dettaglio di confezioni per adulti | Istruzione primaria: scuole elementari | |
|---|---|---|---|---|---|---|---|---|---|---|
| 2010 | 47362 | 24097 | 22961 | 31641 | 38878 | 19373 | 16154 | 19756 | 6493 | 15938 |
| 2011 | 48194 | 26522 | 24920 | 25846 | 34991 | 22127 | 17132 | 21044 | 7759 | 15755 |
| 2012 | 38889 | 30406 | 22053 | 26468 | 36275 | 21870 | 17382 | 17602 | 12108 | 15693 |
| 2013 | 36996 | 26102 | 24273 | 28872 | 28722 | 17394 | 22118 | 17408 | 8736 | 14817 |
| 2014 | 36281 | 31617 | 27560 | 24748 | 25211 | 16518 | 24831 | 16723 | 10391 | 14408 |
| 2015 | 39300 | 35944 | 29257 | 22784 | 19581 | 19763 | 25440 | 17901 | 12554 | 13630 |
| 2016 | 37828 | 34756 | 33961 | 22523 | 16415 | 20997 | 20389 | 17840 | 21416 | 10696 |
| 2017 | 42149 | 49113 | 33412 | 22407 | 19134 | 23292 | 20050 | 18414 | 23463 | 10799 |
| 2018 | 43396 | 52870 | 37154 | 24155 | 20552 | 25800 | 21241 | 19549 | 18537 | 11187 |
| 2019 | 43733 | 56466 | 37965 | 25210 | 18091 | 27254 | 24585 | 19356 | 15031 | 12291 |
| 2020 | 10960 | 27853 | 29759 | 48704 | 12367 | 19223 | 21547 | 17969 | 10138 | 11044 |
| 2021 | 12315 | 29183 | 31992 | 22792 | 11364 | 19356 | 18566 | 19521 | 11142 | 10324 |
dfAttivatiMost.iloc[:, 0:4].plot.bar() #plot 4 most important activated contracts per year
plt.legend(title = 'Four most important activated labours')
<matplotlib.legend.Legend at 0x229c65104f0>
dfAttivatiMost['PIL_MLN_EUR'] = pilgg2['P.I.L. Milioni di Euro']
dfAttivatiMost
| Alberghi | Ristorazione con somministrazione | Attività di produzione cinematografica, di video e di programmi televisivi | Attività di famiglie e convivenze come datori di lavoro per personale domestico | Altri servizi di supporto alle imprese nca | Pulizia generale (non specializzata) di edifici | Istruzione secondaria di primo grado: scuole medie | Costruzione di edifici residenziali e non residenziali | Commercio al dettaglio di confezioni per adulti | Istruzione primaria: scuole elementari | PIL_MLN_EUR | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 | 47362 | 24097 | 22961 | 31641 | 38878 | 19373 | 16154 | 19756 | 6493 | 15938 | 349558 |
| 2011 | 48194 | 26522 | 24920 | 25846 | 34991 | 22127 | 17132 | 21044 | 7759 | 15755 | 357748 |
| 2012 | 38889 | 30406 | 22053 | 26468 | 36275 | 21870 | 17382 | 17602 | 12108 | 15693 | 351390 |
| 2013 | 36996 | 26102 | 24273 | 28872 | 28722 | 17394 | 22118 | 17408 | 8736 | 14817 | 348117 |
| 2014 | 36281 | 31617 | 27560 | 24748 | 25211 | 16518 | 24831 | 16723 | 10391 | 14408 | 355347 |
| 2015 | 39300 | 35944 | 29257 | 22784 | 19581 | 19763 | 25440 | 17901 | 12554 | 13630 | 362330 |
| 2016 | 37828 | 34756 | 33961 | 22523 | 16415 | 20997 | 20389 | 17840 | 21416 | 10696 | 373038 |
| 2017 | 42149 | 49113 | 33412 | 22407 | 19134 | 23292 | 20050 | 18414 | 23463 | 10799 | 383033 |
| 2018 | 43396 | 52870 | 37154 | 24155 | 20552 | 25800 | 21241 | 19549 | 18537 | 11187 | 393500 |
| 2019 | 43733 | 56466 | 37965 | 25210 | 18091 | 27254 | 24585 | 19356 | 15031 | 12291 | 397507 |
| 2020 | 10960 | 27853 | 29759 | 48704 | 12367 | 19223 | 21547 | 17969 | 10138 | 11044 | 365515 |
| 2021 | 12315 | 29183 | 31992 | 22792 | 11364 | 19356 | 18566 | 19521 | 11142 | 10324 | 391101 |
corr = dfAttivatiMost.corr()
sns.set_theme (style = 'white')
heatmap = sns.heatmap(corr, annot = True)
plt.title('Lombardia : most important activated labours')
Text(0.5, 1.0, 'Lombardia : most important activated labours')
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Notiamo una forte correlazione direttamente proporzionale tra il settore della ristorazione e l'incremento del PIL Lombardo.
Parimenti il settore di produzione cinematografica e multimediale è fortemente correlato all'incremento del PIL, in quanto un PIL elevato è indice di evoluzione tecnologica e sociale.
Il settore della ristorazione va di pari passo con la pulizia generale di edifici, in quanto per un servizio di ristorazione professionale è richiesto un controllo e una pulizia di infrastrutture altrettanto professionali.
dfAttivatiMost.boxplot(vert = False) #boxplot most important activated contracts
<AxesSubplot:>
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Correlazione tra i 10 settori più importanti per cessazioni.
La matrice di correlazione evidenzia la correlazione tra i settori terminati e tra settori e PIL
dfCessatiMost = pd.DataFrame(columns=[li2])
for c in li2:
t = dfOrdCess.loc[(dfOrdCess['SETTORE'] == c)].ANNO.value_counts()
dfCessatiMost[c] = t
dfCessatiMost.sort_index(inplace= True)
dfCessatiMost
| Attività di famiglie e convivenze come datori di lavoro per personale domestico | Ristorazione con somministrazione | Costruzione di edifici residenziali e non residenziali | Pulizia generale (non specializzata) di edifici | Altri servizi di supporto alle imprese nca | Trasporto di merci su strada | Bar e altri esercizi simili senza cucina | Servizi logistici relativi alla distribuzione delle merci | Alberghi | Movimento merci relativo ad altri trasporti terrestri | |
|---|---|---|---|---|---|---|---|---|---|---|
| 2010 | 15325 | 13935 | 20432 | 13508 | 19072 | 6449 | 8357 | 2035 | 6312 | 5698 |
| 2011 | 21642 | 15492 | 20954 | 14145 | 17960 | 7300 | 8958 | 3983 | 7792 | 5401 |
| 2012 | 25292 | 18403 | 17682 | 13978 | 15784 | 7008 | 9804 | 5011 | 6368 | 5610 |
| 2013 | 24870 | 16707 | 15620 | 13388 | 14512 | 6651 | 8339 | 5285 | 6292 | 4590 |
| 2014 | 22037 | 16379 | 14049 | 10847 | 12414 | 6471 | 7221 | 6253 | 6111 | 4829 |
| 2015 | 21551 | 16796 | 13906 | 12693 | 13120 | 6695 | 6072 | 5514 | 5655 | 5342 |
| 2016 | 20289 | 16232 | 12639 | 11356 | 11460 | 6264 | 5801 | 5978 | 3892 | 4019 |
| 2017 | 21606 | 18369 | 12740 | 10889 | 8421 | 7452 | 6581 | 6139 | 4134 | 4636 |
| 2018 | 22192 | 20816 | 12773 | 11730 | 9932 | 8261 | 7503 | 6124 | 4750 | 4250 |
| 2019 | 21743 | 22227 | 12366 | 13772 | 9615 | 9374 | 7580 | 9314 | 5163 | 6027 |
| 2020 | 23392 | 15686 | 8692 | 10914 | 6123 | 6988 | 5161 | 7266 | 3776 | 3470 |
| 2021 | 18744 | 11595 | 9226 | 8057 | 4753 | 7181 | 3920 | 6297 | 1744 | 2953 |
dfCessatiMost.iloc[:, 0:4].plot.bar() #plot 4 most imprtant ceased contracts per year
plt.legend(title = 'Four most important ceased labours')
<matplotlib.legend.Legend at 0x229df1be3a0>
dfCessatiMost['PIL_MLN_EUR'] = pilgg2['P.I.L. Milioni di Euro']
dfCessatiMost
| Attività di famiglie e convivenze come datori di lavoro per personale domestico | Ristorazione con somministrazione | Costruzione di edifici residenziali e non residenziali | Pulizia generale (non specializzata) di edifici | Altri servizi di supporto alle imprese nca | Trasporto di merci su strada | Bar e altri esercizi simili senza cucina | Servizi logistici relativi alla distribuzione delle merci | Alberghi | Movimento merci relativo ad altri trasporti terrestri | PIL_MLN_EUR | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 | 15325 | 13935 | 20432 | 13508 | 19072 | 6449 | 8357 | 2035 | 6312 | 5698 | 349558 |
| 2011 | 21642 | 15492 | 20954 | 14145 | 17960 | 7300 | 8958 | 3983 | 7792 | 5401 | 357748 |
| 2012 | 25292 | 18403 | 17682 | 13978 | 15784 | 7008 | 9804 | 5011 | 6368 | 5610 | 351390 |
| 2013 | 24870 | 16707 | 15620 | 13388 | 14512 | 6651 | 8339 | 5285 | 6292 | 4590 | 348117 |
| 2014 | 22037 | 16379 | 14049 | 10847 | 12414 | 6471 | 7221 | 6253 | 6111 | 4829 | 355347 |
| 2015 | 21551 | 16796 | 13906 | 12693 | 13120 | 6695 | 6072 | 5514 | 5655 | 5342 | 362330 |
| 2016 | 20289 | 16232 | 12639 | 11356 | 11460 | 6264 | 5801 | 5978 | 3892 | 4019 | 373038 |
| 2017 | 21606 | 18369 | 12740 | 10889 | 8421 | 7452 | 6581 | 6139 | 4134 | 4636 | 383033 |
| 2018 | 22192 | 20816 | 12773 | 11730 | 9932 | 8261 | 7503 | 6124 | 4750 | 4250 | 393500 |
| 2019 | 21743 | 22227 | 12366 | 13772 | 9615 | 9374 | 7580 | 9314 | 5163 | 6027 | 397507 |
| 2020 | 23392 | 15686 | 8692 | 10914 | 6123 | 6988 | 5161 | 7266 | 3776 | 3470 | 365515 |
| 2021 | 18744 | 11595 | 9226 | 8057 | 4753 | 7181 | 3920 | 6297 | 1744 | 2953 | 391101 |
corr2 = dfCessatiMost.corr()
sns.set_theme (style = 'white')
heatmap2 = sns.heatmap(corr2, annot = True)
plt.title('Lombardia : most important ceased labours')
Text(0.5, 1.0, 'Lombardia : most important ceased labours')
VISUALIZZAZIONE DEI DATI, CONSIDERAZIONI E CONFRONTO TRA LE STATISTICHE DEI LAVORI CESSATI E ATTIVATI NEI SETTORI PIU IMPORTANTI PER FREQUENZA DI ATTIVAZIONE/CESSAZIONE:
Notiamo una forte correlazione tra la terminazione dei contratti relativi al trasporto e l'incremento del PIL. Con il processo di digitalizzazione e innovazione tecnica è probabile che tali posizioni vengano considerate meno importanti e non risultano quindi un target interessante per la popolazione
dfCessatiMost.boxplot(vert = False) #boxplot most ceased contracts
<AxesSubplot:>
ANALISI TEMPORALE E PREPARAZIONE DEI DATI PER L'IMPLEMENTAZIONE DI UN MODELLO DI PREDITTIVITÀ CHE CONSIDERI ANDAMENTO DEL MERCATO LAVORATIVO SU ATTIVAZIONI E CESSAZIONI:
Visualizzazione dele serie temporali mensili per i dieci tipi di contratti attivati più frequentemente
attFrames = []
for val in perAtt.index: #visualize
na = attivHead.loc[(attivHead['SETTORE'] == val)]
h = na.resample('M').count()
attFrames.append(h)
na2 = h.rename (columns = {'SETTORE' :
('ATTIVAZIONI: '+ val)}).loc[:, ['ATTIVAZIONI: '+ val,]]
na2.plot(color=np.random.rand(3,), legend = val, figsize = (20,10))
fig, axes = plt.subplots(1,2,figsize=(20,6), dpi= 120)
plot_acf(h.SETTORE.tolist(), lags=50, ax=axes[0],
title = 'Acr: ' + val)
plot_pacf(h.SETTORE.tolist(), lags=50, ax=axes[1],
title = 'Partial acr: '+ val)
plt.show()
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
attFrames
[ CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 3767 3767 3767 3767 3767 3767 3767 3767
2010-02-28 3592 3592 3592 3592 3592 3592 3592 3592
2010-03-31 3528 3528 3528 3528 3528 3528 3528 3528
2010-04-30 3293 3293 3293 3293 3293 3293 3293 3293
2010-05-31 3823 3823 3823 3823 3823 3823 3823 3823
... ... ... ... ... ... ... ... ...
2021-08-31 789 789 789 789 789 789 789 789
2021-09-30 1174 1174 1174 1174 1174 1174 1174 1174
2021-10-31 1337 1337 1337 1337 1337 1337 1337 1337
2021-11-30 946 946 946 946 946 946 946 946
2021-12-31 782 782 782 782 782 782 782 782
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 3767 3767 3767
2010-02-28 3592 3592 3592
2010-03-31 3528 3528 3528
2010-04-30 3293 3293 3293
2010-05-31 3823 3823 3823
... ... ... ...
2021-08-31 789 789 789
2021-09-30 1174 1174 1174
2021-10-31 1337 1337 1337
2021-11-30 946 946 946
2021-12-31 782 782 782
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 2254 2254 2254 2254 2254 2254 2254 2254
2010-02-28 2139 2139 2139 2139 2139 2139 2139 2139
2010-03-31 1869 1869 1869 1869 1869 1869 1869 1869
2010-04-30 1867 1867 1867 1867 1867 1867 1867 1867
2010-05-31 2054 2054 2054 2054 2054 2054 2054 2054
... ... ... ... ... ... ... ... ...
2021-08-31 2016 2016 2016 2016 2016 2016 2016 2016
2021-09-30 2401 2401 2401 2401 2401 2401 2401 2401
2021-10-31 2467 2467 2467 2467 2467 2467 2467 2467
2021-11-30 2042 2042 2042 2042 2042 2042 2042 2042
2021-12-31 1796 1796 1796 1796 1796 1796 1796 1796
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 2254 2254 2254
2010-02-28 2139 2139 2139
2010-03-31 1869 1869 1869
2010-04-30 1867 1867 1867
2010-05-31 2054 2054 2054
... ... ... ...
2021-08-31 2016 2016 2016
2021-09-30 2401 2401 2401
2021-10-31 2467 2467 2467
2021-11-30 2042 2042 2042
2021-12-31 1796 1796 1796
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 1908 1908 1908 1908 1908 1908 1908 1908
2010-02-28 1933 1933 1933 1933 1933 1933 1933 1933
2010-03-31 1938 1938 1938 1938 1938 1938 1938 1938
2010-04-30 1687 1687 1687 1687 1687 1687 1687 1687
2010-05-31 2180 2180 2180 2180 2180 2180 2180 2180
... ... ... ... ... ... ... ... ...
2021-08-31 2910 2910 2910 2910 2910 2910 2910 2910
2021-09-30 2836 2836 2836 2836 2836 2836 2836 2836
2021-10-31 2061 2061 2061 2061 2061 2061 2061 2061
2021-11-30 2192 2192 2192 2192 2192 2192 2192 2192
2021-12-31 2861 2861 2861 2861 2861 2861 2861 2861
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 1908 1908 1908
2010-02-28 1933 1933 1933
2010-03-31 1938 1938 1938
2010-04-30 1687 1687 1687
2010-05-31 2180 2180 2180
... ... ... ...
2021-08-31 2910 2910 2910
2021-09-30 2836 2836 2836
2021-10-31 2061 2061 2061
2021-11-30 2192 2192 2192
2021-12-31 2861 2861 2861
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 3039 3039 3039 3039 3039 3039 3039 3039
2010-02-28 2658 2658 2658 2658 2658 2658 2658 2658
2010-03-31 2591 2591 2591 2591 2591 2591 2591 2591
2010-04-30 2532 2532 2532 2532 2532 2532 2532 2532
2010-05-31 2374 2374 2374 2374 2374 2374 2374 2374
... ... ... ... ... ... ... ... ...
2021-08-31 1853 1853 1853 1853 1853 1853 1853 1853
2021-09-30 1927 1927 1927 1927 1927 1927 1927 1927
2021-10-31 1560 1560 1560 1560 1560 1560 1560 1560
2021-11-30 1501 1501 1501 1501 1501 1501 1501 1501
2021-12-31 1712 1712 1712 1712 1712 1712 1712 1712
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 3039 3039 3039
2010-02-28 2658 2658 2658
2010-03-31 2591 2591 2591
2010-04-30 2532 2532 2532
2010-05-31 2374 2374 2374
... ... ... ...
2021-08-31 1853 1853 1853
2021-09-30 1927 1927 1927
2021-10-31 1560 1560 1560
2021-11-30 1501 1501 1501
2021-12-31 1712 1712 1712
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 3855 3855 3855 3855 3855 3855 3855 3855
2010-02-28 3368 3368 3368 3368 3368 3368 3368 3368
2010-03-31 2864 2864 2864 2864 2864 2864 2864 2864
2010-04-30 3157 3157 3157 3157 3157 3157 3157 3157
2010-05-31 2976 2976 2976 2976 2976 2976 2976 2976
... ... ... ... ... ... ... ... ...
2021-08-31 1028 1028 1028 1028 1028 1028 1028 1028
2021-09-30 948 948 948 948 948 948 948 948
2021-10-31 991 991 991 991 991 991 991 991
2021-11-30 712 712 712 712 712 712 712 712
2021-12-31 878 878 878 878 878 878 878 878
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 3855 3855 3855
2010-02-28 3368 3368 3368
2010-03-31 2864 2864 2864
2010-04-30 3157 3157 3157
2010-05-31 2976 2976 2976
... ... ... ...
2021-08-31 1028 1028 1028
2021-09-30 948 948 948
2021-10-31 991 991 991
2021-11-30 712 712 712
2021-12-31 878 878 878
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 1433 1433 1433 1433 1433 1433 1433 1433
2010-02-28 1425 1425 1425 1425 1425 1425 1425 1425
2010-03-31 1382 1382 1382 1382 1382 1382 1382 1382
2010-04-30 1729 1729 1729 1729 1729 1729 1729 1729
2010-05-31 1480 1480 1480 1480 1480 1480 1480 1480
... ... ... ... ... ... ... ... ...
2021-08-31 2033 2033 2033 2033 2033 2033 2033 2033
2021-09-30 1844 1844 1844 1844 1844 1844 1844 1844
2021-10-31 1317 1317 1317 1317 1317 1317 1317 1317
2021-11-30 1844 1844 1844 1844 1844 1844 1844 1844
2021-12-31 2277 2277 2277 2277 2277 2277 2277 2277
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 1433 1433 1433
2010-02-28 1425 1425 1425
2010-03-31 1382 1382 1382
2010-04-30 1729 1729 1729
2010-05-31 1480 1480 1480
... ... ... ...
2021-08-31 2033 2033 2033
2021-09-30 1844 1844 1844
2021-10-31 1317 1317 1317
2021-11-30 1844 1844 1844
2021-12-31 2277 2277 2277
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 1002 1002 1002 1002 1002 1002 1002 1002
2010-02-28 1455 1455 1455 1455 1455 1455 1455 1455
2010-03-31 1642 1642 1642 1642 1642 1642 1642 1642
2010-04-30 1554 1554 1554 1554 1554 1554 1554 1554
2010-05-31 694 694 694 694 694 694 694 694
... ... ... ... ... ... ... ... ...
2021-08-31 1683 1683 1683 1683 1683 1683 1683 1683
2021-09-30 1744 1744 1744 1744 1744 1744 1744 1744
2021-10-31 1718 1718 1718 1718 1718 1718 1718 1718
2021-11-30 1491 1491 1491 1491 1491 1491 1491 1491
2021-12-31 1287 1287 1287 1287 1287 1287 1287 1287
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 1002 1002 1002
2010-02-28 1455 1455 1455
2010-03-31 1642 1642 1642
2010-04-30 1554 1554 1554
2010-05-31 694 694 694
... ... ... ...
2021-08-31 1683 1683 1683
2021-09-30 1744 1744 1744
2021-10-31 1718 1718 1718
2021-11-30 1491 1491 1491
2021-12-31 1287 1287 1287
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 2202 2202 2202 2202 2202 2202 2202 2202
2010-02-28 1679 1679 1679 1679 1679 1679 1679 1679
2010-03-31 1646 1646 1646 1646 1646 1646 1646 1646
2010-04-30 1532 1532 1532 1532 1532 1532 1532 1532
2010-05-31 1777 1777 1777 1777 1777 1777 1777 1777
... ... ... ... ... ... ... ... ...
2021-08-31 1629 1629 1629 1629 1629 1629 1629 1629
2021-09-30 1561 1561 1561 1561 1561 1561 1561 1561
2021-10-31 1202 1202 1202 1202 1202 1202 1202 1202
2021-11-30 1253 1253 1253 1253 1253 1253 1253 1253
2021-12-31 1370 1370 1370 1370 1370 1370 1370 1370
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 2202 2202 2202
2010-02-28 1679 1679 1679
2010-03-31 1646 1646 1646
2010-04-30 1532 1532 1532
2010-05-31 1777 1777 1777
... ... ... ...
2021-08-31 1629 1629 1629
2021-09-30 1561 1561 1561
2021-10-31 1202 1202 1202
2021-11-30 1253 1253 1253
2021-12-31 1370 1370 1370
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 497 497 497 497 497 497 497 497
2010-02-28 418 418 418 418 418 418 418 418
2010-03-31 497 497 497 497 497 497 497 497
2010-04-30 607 607 607 607 607 607 607 607
2010-05-31 644 644 644 644 644 644 644 644
... ... ... ... ... ... ... ... ...
2021-08-31 257 257 257 257 257 257 257 257
2021-09-30 1462 1462 1462 1462 1462 1462 1462 1462
2021-10-31 2235 2235 2235 2235 2235 2235 2235 2235
2021-11-30 4060 4060 4060 4060 4060 4060 4060 4060
2021-12-31 1357 1357 1357 1357 1357 1357 1357 1357
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 497 497 497
2010-02-28 418 418 418
2010-03-31 497 497 497
2010-04-30 607 607 607
2010-05-31 644 644 644
... ... ... ...
2021-08-31 257 257 257
2021-09-30 1462 1462 1462
2021-10-31 2235 2235 2235
2021-11-30 4060 4060 4060
2021-12-31 1357 1357 1357
[144 rows x 11 columns],
CONTRATTO CONTR_N SETTORE SETT_ID STATO ETA GENERE DATE \
DATA
2010-01-31 1251 1251 1251 1251 1251 1251 1251 1251
2010-02-28 1463 1463 1463 1463 1463 1463 1463 1463
2010-03-31 1704 1704 1704 1704 1704 1704 1704 1704
2010-04-30 1160 1160 1160 1160 1160 1160 1160 1160
2010-05-31 855 855 855 855 855 855 855 855
... ... ... ... ... ... ... ... ...
2021-08-31 948 948 948 948 948 948 948 948
2021-09-30 1073 1073 1073 1073 1073 1073 1073 1073
2021-10-31 1219 1219 1219 1219 1219 1219 1219 1219
2021-11-30 667 667 667 667 667 667 667 667
2021-12-31 759 759 759 759 759 759 759 759
MESE ANNO PIL MLN EUR ANNUO
DATA
2010-01-31 1251 1251 1251
2010-02-28 1463 1463 1463
2010-03-31 1704 1704 1704
2010-04-30 1160 1160 1160
2010-05-31 855 855 855
... ... ... ...
2021-08-31 948 948 948
2021-09-30 1073 1073 1073
2021-10-31 1219 1219 1219
2021-11-30 667 667 667
2021-12-31 759 759 759
[144 rows x 11 columns]]
len(attFrames[0])
144
ANALISI TEMPORALE E PREPARAZIONE DEI DATI PER L'IMPLEMENTAZIONE DI UN MODELLO DI PREDITTIVITÀ CHE CONSIDERI ANDAMENTO DEL MERCATO LAVORATIVO SU ATTIVAZIONI E CESSAZIONI:
Visualizzazione dele serie temporali mensili per i dieci tipi di contratti cessati più frequentemente
CESSATI ORA
cessFrames = []
for val in perCess.index:
na = cessHead.loc[(cessHead['SETTORE'] == val)]
h = na.resample('M').count()
cessFrames.append(h)
na2 = h.rename (columns = {'SETTORE' :
('CESSAZIONI: '+ val)}).loc[:, ['CESSAZIONI: '+ val,]]
na2.plot(color=np.random.rand(3,), legend = val, figsize = (20,10))
fig, axes = plt.subplots(1,2,figsize=(20,6), dpi= 120)
plot_acf(h.SETTORE.tolist(), lags=50, ax=axes[0],
title = 'Acr: ' + val)
plot_pacf(h.SETTORE.tolist(), lags=50, ax=axes[1],
title = 'Partial acr: '+ val)
plt.show()
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
totaliAttivatiTs = dfOrdAtt.copy()
totaliCessatiTs = dfOrdCess.copy()
attAnnuali = totaliAttivatiTs.resample('Y').count().iloc[:, [2]]
cessAnnuali = totaliCessatiTs.resample('Y').count().iloc[:, [2]]
attAnnuali.rename(columns={'SETTORE': 'N.ATTIVATI'}, inplace=True)
cessAnnuali.rename(columns={'SETTORE': 'N.CESSATI'}, inplace=True)
ax = attAnnuali.plot(kind="bar", color = "orange")
cessAnnuali.plot( kind="bar", ax=ax, color="red")
<AxesSubplot:xlabel='DATA'>
attTimeSe = totaliAttivatiTs.resample('M').count().iloc[:, [2]]
cessTimeSe = totaliCessatiTs.resample('M').count().iloc[:, [2]]
attTimeSe.rename(columns={'SETTORE': 'N.ATTIVATI'}, inplace=True)
cessTimeSe.rename(columns={'SETTORE': 'N.CESSATI'}, inplace=True)
APPLICAZIONE DI MODELLI PREDITTIVI (AUTO ARIMA) SULLE TIME SERIES DI CONTRATTI ATTIVATI:
Analisi, scomposizione e test della stazionarità della serie di contratti attivati e implementazione del modello AUTO - ARIMA
attTimeSe.plot()
<AxesSubplot:xlabel='DATA'>
plot_pacf(attTimeSe)
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\statsmodels\graphics\tsaplots.py:348: FutureWarning: The default method 'yw' can produce PACF values outside of the [-1,1] interval. After 0.13, the default will change tounadjusted Yule-Walker ('ywm'). You can use this method now by setting method='ywm'.
warnings.warn(
cgs =attTimeSe
analysis = cgs['N.ATTIVATI'].copy()
decompose_result_mult = seasonal_decompose(analysis, model="multiplicative")
trend = decompose_result_mult.trend
seasonal = decompose_result_mult.seasonal
residual = decompose_result_mult.resid
decompose_result_mult.plot();
# Additive decomposition
decadd = seasonal_decompose(analysis, model="additive")
add = decadd.plot()
plt.show()
toStation = analysis.diff().dropna()
plt.figure(figsize=(12,5))
ax1 = toStation.plot()
ax1.set_xlabel("Date")
ax1.set_ylabel("Count")
plt.grid(True)
plt.show()
APPLICAZIONE DI MODELLI PREDITTIVI (AUTO ARIMA) SULLE TIME SERIES DI CONTRATTI ATTIVATI:
Adfuller test è utilizzato per verificare la stazionarità di una serie storica. Una serie è stazionaria quando la media dei valori rappresentati dalla funzione non dipende dal tempo, similmente la covarianza della stessa non ha dipendenze con le osservazioni temporali. Pertanto se il p value calcolato dal test risulta maggiore a 0,05 prima e dopo il test di differenziazione possiamo affermare che la serie non presenta una componente stazionaria, ma ha delle dipendenze con il tempo. Questo implica automaticamente che esiste seppure talvolta non esplicita una stagionalità sulla serie.
test_result=adfuller(attTimeSe['N.ATTIVATI'])
def adfuller_test(vls):
result=adfuller(vls)
labels = ['ADF Test Statistic','p-value','#Lags Used','Number of Observations']
for value,label in zip(result,labels):
print(label+' : '+str(value) )
if test_result[1] <= 0.05:
print("strong evidence against the null hypothesis(Ho),result < 0.05, reject the null hypothesis. Data is stationary")
else:
print("weak evidence against null hypothesis, result > 0,05, indicating it is non-stationary ")
adfuller_test(attTimeSe['N.ATTIVATI'])
weak evidence against null hypothesis, result > 0,05, indicating it is non-stationary ADF Test Statistic : -0.8645322360982132 p-value : 0.7994280243739811 #Lags Used : 10 Number of Observations : 133
attTimeSe['Difference'] = attTimeSe['N.ATTIVATI'] - attTimeSe['N.ATTIVATI'].shift(1)
attTimeSe['Seasonal First Difference']=attTimeSe['N.ATTIVATI']-attTimeSe['N.ATTIVATI'].shift(12)
attTimeSe.head()
| N.ATTIVATI | Difference | Seasonal First Difference | |
|---|---|---|---|
| DATA | |||
| 2010-01-31 | 61434 | NaN | NaN |
| 2010-02-28 | 55401 | -6033.0 | NaN |
| 2010-03-31 | 57889 | 2488.0 | NaN |
| 2010-04-30 | 57900 | 11.0 | NaN |
| 2010-05-31 | 59538 | 1638.0 | NaN |
# Again testing if data is stationary
adfuller_test(attTimeSe['Seasonal First Difference'].dropna())
ADF Test Statistic : -2.719896118345244 p-value : 0.07065819658515171 #Lags Used : 11 Number of Observations : 120
tfram2 = attTimeSe['N.ATTIVATI']
tfram2
DATA
2010-01-31 61434
2010-02-28 55401
2010-03-31 57889
2010-04-30 57900
2010-05-31 59538
...
2021-08-31 59683
2021-09-30 55403
2021-10-31 47578
2021-11-30 54033
2021-12-31 55282
Freq: M, Name: N.ATTIVATI, Length: 144, dtype: int64
stepwise_model = auto_arima(tfram2, start_p=1, start_q=1,
max_p=3, max_q=3, m=12,
start_P=0, seasonal=True, #non stationary ts requires seasonality capturing mechanism
d=1, D=1, trace=True,
error_action='ignore',
suppress_warnings=True,
stepwise=True)
print(stepwise_model.aic())
Performing stepwise search to minimize aic ARIMA(1,1,1)(0,1,1)[12] : AIC=2876.339, Time=0.43 sec ARIMA(0,1,0)(0,1,0)[12] : AIC=2963.621, Time=0.02 sec ARIMA(1,1,0)(1,1,0)[12] : AIC=2925.239, Time=0.15 sec ARIMA(0,1,1)(0,1,1)[12] : AIC=2876.769, Time=0.18 sec ARIMA(1,1,1)(0,1,0)[12] : AIC=2919.553, Time=0.14 sec ARIMA(1,1,1)(1,1,1)[12] : AIC=2878.262, Time=0.53 sec ARIMA(1,1,1)(0,1,2)[12] : AIC=2878.235, Time=1.05 sec ARIMA(1,1,1)(1,1,0)[12] : AIC=2897.925, Time=0.53 sec ARIMA(1,1,1)(1,1,2)[12] : AIC=inf, Time=3.32 sec ARIMA(1,1,0)(0,1,1)[12] : AIC=2901.961, Time=0.17 sec ARIMA(2,1,1)(0,1,1)[12] : AIC=2859.754, Time=0.33 sec ARIMA(2,1,1)(0,1,0)[12] : AIC=2906.863, Time=0.13 sec ARIMA(2,1,1)(1,1,1)[12] : AIC=2860.501, Time=0.44 sec ARIMA(2,1,1)(0,1,2)[12] : AIC=2860.152, Time=0.85 sec ARIMA(2,1,1)(1,1,0)[12] : AIC=2885.464, Time=0.28 sec ARIMA(2,1,1)(1,1,2)[12] : AIC=2861.562, Time=1.23 sec ARIMA(2,1,0)(0,1,1)[12] : AIC=2864.032, Time=0.43 sec ARIMA(3,1,1)(0,1,1)[12] : AIC=2861.740, Time=0.54 sec ARIMA(2,1,2)(0,1,1)[12] : AIC=2863.856, Time=0.41 sec ARIMA(1,1,2)(0,1,1)[12] : AIC=2878.226, Time=0.28 sec ARIMA(3,1,0)(0,1,1)[12] : AIC=2858.875, Time=0.32 sec ARIMA(3,1,0)(0,1,0)[12] : AIC=2904.559, Time=0.11 sec ARIMA(3,1,0)(1,1,1)[12] : AIC=2859.467, Time=0.46 sec ARIMA(3,1,0)(0,1,2)[12] : AIC=2859.107, Time=0.66 sec ARIMA(3,1,0)(1,1,0)[12] : AIC=2883.872, Time=0.24 sec ARIMA(3,1,0)(1,1,2)[12] : AIC=2860.639, Time=1.14 sec ARIMA(3,1,0)(0,1,1)[12] intercept : AIC=2860.049, Time=0.64 sec Best model: ARIMA(3,1,0)(0,1,1)[12] Total fit time: 15.024 seconds 2858.8751711603436
fig = stepwise_model.plot_diagnostics()
fig.set_size_inches(18.5, 10.5, forward=True)
plt.show()
# Train Test Split Index
train_size = 0.88
split_idx = round(len(tfram2)* train_size)
split_idx
# Split
train = tfram2.iloc[:split_idx]
test = tfram2.iloc[split_idx:]
# Visualize split
fig,ax= plt.subplots(figsize=(12,8))
kws = dict(marker='o')
plt.plot(train, label='Train', **kws)
plt.plot(test, label='Test', **kws)
ax.legend(bbox_to_anchor=[1,1]);
stepwise_model.fit(train)
ARIMA(order=(3, 1, 0), scoring_args={}, seasonal_order=(0, 1, 1, 12),
suppress_warnings=True, with_intercept=False)
future_forecast, cf = stepwise_model.predict(n_periods=17, return_conf_int=True)
future_forecast = pd.DataFrame(future_forecast,index = test.index, columns=['Prediction'])
kwsnep = dict(marker='o')
cc = pd.concat([test,future_forecast],axis=1)
cc.plot(**kwsnep, figsize=(20, 10))
<AxesSubplot:xlabel='DATA'>
index_of_fc = pd.date_range(tfram2.index[-1], periods = 17, freq='MS')
future_forecast_3 = future_forecast
future_forecast_3 = future_forecast_3.set_index(index_of_fc)
# Plot Della prediction
plt.figure(figsize=(25, 15))
kwsn = dict(marker='o')
plt.plot(tfram2, color='blue', label='Actual Date', **kwsn)
plt.plot(future_forecast_3, color='red', label='Predict', **kwsn)
plt.legend(loc='lower right', fontsize=15)
plt.title("Predizione attivati")
plt.show()
APPLICAZIONE DI MODELLI PREDITTIVI (AUTO ARIMA) SULLE TIME SERIES DI CONTRATTI ATTIVATI:
Considerazioni: Il test rivela che non è presente stazionarità, ovvero che la media e la covarianza della funzione temporale sono dipendenti dal tempo. Abbiamo applicato il modello di predizione AUTO-ARIMA con stagionalità (ovvero AUTO - SARIMA).
La stagionalità a giudicare dal grafico di autocorrelazione non è eccessivamente marcata. Una implementazione alternativa che potrebbe garantire risultati migliori potrebbe essere quella di convertire la funzione in logaritmica ed effettuare una differenziazione per ridurre la componente stagionale e applicare il classico modello ARIMA.
mape = mean_absolute_percentage_error(test, future_forecast_3.Prediction)
print(mape)
0.1433354671416055
MSE = mean_squared_error(test, future_forecast_3)
RMSE = math.sqrt(MSE)
print('The mean square error is: ', MSE)
print('The Root Mean Square error is: ', RMSE)
The mean square error is: 118219597.59521176 The Root Mean Square error is: 10872.883591541471
APPLICAZIONE DI MODELLI PREDITTIVI (AUTO ARIMA) SULLE TIME SERIES DI CONTRATTI CESSATI:
Analisi, scomposizione e test della stazionarità della serie di contratti cessati e implementazione del modello AUTO - ARIMA
cessTimeSe.plot()
<AxesSubplot:xlabel='DATA'>
plot_acf(cessTimeSe)
analysis = cessTimeSe['N.CESSATI'].copy()
decompose_result_mult = seasonal_decompose(analysis, model="multiplicative")
trend = decompose_result_mult.trend
seasonal = decompose_result_mult.seasonal
residual = decompose_result_mult.resid
decompose_result_mult.plot();
# Additive decomposition
decadd = seasonal_decompose(analysis, model="additive")
add = decadd.plot()
plt.show()
toStation = analysis.diff().dropna()
plt.figure(figsize=(12,5))
ax1 = toStation.plot()
ax1.set_xlabel("Date")
ax1.set_ylabel("Count")
plt.grid(True)
plt.show()
APPLICAZIONE DI MODELLI PREDITTIVI (AUTO ARIMA) SULLE TIME SERIES DI CONTRATTI CESSATI:
Adfuller test è utilizzato per verificare la stazionarità di una serie storica. Una serie è stazionaria quando la media dei valor rappresentati dalla funzione non dipende dal tempo, similmente la covarianza della stessa non ha dipendenze con le osservazioni temporali. Pertanto se il p value calcolato dall test risulta maggiore a 0,05 prima e dopo il test di differenziazione possiamo affermare che la serie non presenta una componente stazionaria, ma ha delle dipendenze con il tempo. Questo implica automaticamente che esiste seppure talvolta non esplicita una stagionalità sulla serie.
test_result=adfuller(cessTimeSe['N.CESSATI'])
adfuller_test(cessTimeSe['N.CESSATI'])
ADF Test Statistic : 0.29783007172434917 p-value : 0.9772447120881198 #Lags Used : 11 Number of Observations : 132
cessTimeSe['Difference'] = cessTimeSe['N.CESSATI'] - cessTimeSe['N.CESSATI'].shift(1)
cessTimeSe['Seasonal First Difference']=cessTimeSe['N.CESSATI']-cessTimeSe['N.CESSATI'].shift(12)
cessTimeSe.head()
| N.CESSATI | Difference | Seasonal First Difference | |
|---|---|---|---|
| DATA | |||
| 2010-01-31 | 52120 | NaN | NaN |
| 2010-02-28 | 44051 | -8069.0 | NaN |
| 2010-03-31 | 31956 | -12095.0 | NaN |
| 2010-04-30 | 37181 | 5225.0 | NaN |
| 2010-05-31 | 26362 | -10819.0 | NaN |
adfuller_test(cessTimeSe['Seasonal First Difference'].dropna())
ADF Test Statistic : -2.1073010143852637 p-value : 0.2415889796826256 #Lags Used : 11 Number of Observations : 120
tfram3 = cessTimeSe['N.CESSATI']
stepwise_model2 = auto_arima(tfram3, start_p=1, start_q=1,
max_p=3, max_q=3, m=12,
start_P=0, seasonal=True,
d=1, D=1, trace=True,
error_action='ignore',
suppress_warnings=True,
stepwise=True)
print(stepwise_model2.aic())
Performing stepwise search to minimize aic ARIMA(1,1,1)(0,1,1)[12] : AIC=2640.572, Time=0.35 sec ARIMA(0,1,0)(0,1,0)[12] : AIC=2752.956, Time=0.03 sec ARIMA(1,1,0)(1,1,0)[12] : AIC=2699.760, Time=0.13 sec ARIMA(0,1,1)(0,1,1)[12] : AIC=2637.125, Time=0.46 sec ARIMA(0,1,1)(0,1,0)[12] : AIC=2677.337, Time=0.06 sec ARIMA(0,1,1)(1,1,1)[12] : AIC=2641.473, Time=0.68 sec ARIMA(0,1,1)(0,1,2)[12] : AIC=2641.425, Time=1.62 sec ARIMA(0,1,1)(1,1,0)[12] : AIC=2657.064, Time=0.26 sec ARIMA(0,1,1)(1,1,2)[12] : AIC=2639.874, Time=1.18 sec ARIMA(0,1,0)(0,1,1)[12] : AIC=inf, Time=0.48 sec ARIMA(0,1,2)(0,1,1)[12] : AIC=2652.470, Time=0.29 sec ARIMA(1,1,0)(0,1,1)[12] : AIC=2678.273, Time=0.16 sec ARIMA(1,1,2)(0,1,1)[12] : AIC=2629.745, Time=1.07 sec ARIMA(1,1,2)(0,1,0)[12] : AIC=2668.670, Time=0.33 sec ARIMA(1,1,2)(1,1,1)[12] : AIC=2633.823, Time=1.54 sec ARIMA(1,1,2)(0,1,2)[12] : AIC=2655.123, Time=1.85 sec ARIMA(1,1,2)(1,1,0)[12] : AIC=2643.399, Time=0.98 sec ARIMA(1,1,2)(1,1,2)[12] : AIC=inf, Time=2.83 sec ARIMA(2,1,2)(0,1,1)[12] : AIC=2641.895, Time=0.48 sec ARIMA(1,1,3)(0,1,1)[12] : AIC=2629.152, Time=1.64 sec ARIMA(1,1,3)(0,1,0)[12] : AIC=2666.158, Time=0.21 sec ARIMA(1,1,3)(1,1,1)[12] : AIC=2639.457, Time=1.70 sec ARIMA(1,1,3)(0,1,2)[12] : AIC=2646.939, Time=3.58 sec ARIMA(1,1,3)(1,1,0)[12] : AIC=2654.086, Time=0.66 sec ARIMA(1,1,3)(1,1,2)[12] : AIC=inf, Time=3.58 sec ARIMA(0,1,3)(0,1,1)[12] : AIC=2651.763, Time=0.35 sec ARIMA(2,1,3)(0,1,1)[12] : AIC=inf, Time=1.69 sec ARIMA(1,1,3)(0,1,1)[12] intercept : AIC=2652.016, Time=0.59 sec Best model: ARIMA(1,1,3)(0,1,1)[12] Total fit time: 28.788 seconds 2629.1524349926863
fig = stepwise_model2.plot_diagnostics()
fig.set_size_inches(18.5, 10.5, forward=True)
plt.show()
# Train Test Split Index
train_size = 0.85
split_idx = round(len(tfram3)* train_size)
split_idx
# Split
train2 = tfram3.iloc[:split_idx]
test2 = tfram3.iloc[split_idx:]
# Visualize split
fig,ax= plt.subplots(figsize=(12,8))
kws = dict(marker='o')
plt.plot(train2, label='Train', **kws)
plt.plot(test2, label='Test', **kws)
ax.legend(bbox_to_anchor=[1,1]);
stepwise_model2.fit(train2)
ARIMA(order=(1, 1, 3), scoring_args={}, seasonal_order=(0, 1, 1, 12),
suppress_warnings=True, with_intercept=False)
future, cf2 = stepwise_model2.predict(n_periods=22, return_conf_int=True)
future = pd.DataFrame(future,index = test2.index, columns=['Prediction'])
cc = pd.concat([test2,future],axis=1)
cc.plot(**kwsnep, figsize=(20, 10))
<AxesSubplot:xlabel='DATA'>
index_of = pd.date_range(tfram3.index[-1], periods = 22, freq='MS')
future_forecast_4 = future
future_forecast_4 = future_forecast_4.set_index(index_of)
# Plot Della prediction
plt.figure(figsize=(25, 15))
plt.plot(tfram3, color='blue', label='Actual Date', **kwsn)
plt.plot(future_forecast_4, color='red', label='Predict', **kwsn)
plt.legend(loc='lower right', fontsize=15)
plt.title("Predizione cessati")
plt.show()
mape = mean_absolute_percentage_error(test2, future_forecast_4.Prediction)
print(mape)
0.2081571585254859
MSE = mean_squared_error(test2, future_forecast_4)
RMSE = math.sqrt(MSE)
print('The mean square error is: ', MSE)
print('The Root Mean Square error is: ', RMSE)
The mean square error is: 26336112.14437239 The Root Mean Square error is: 5131.872187065105
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Il settore della ristorzione ha un turnover considerevole,ed è in seconda posizione per quanto riguarda le attivazioni dei contratti e cessazioni.
Osservando i due grafici, rispettivamente la predizione delle attivazioni e quella delle cessazioni notiamo che la crisi relativa al COVID ha causato un decremento importante nel pil della lombradia e un calo delle attivazioni di contratti nel generale. Le cessazioni seguono un andamento stagionale, previsto dal modello utilizzato e impostato in modo da tener conto della stagionalità.
Nonostante la crisi da covid abbia impattato molto sul settore della ristorazione, dimostrato dalla concavità della funizione temporale delle attivazioni dei contratti in ambito ristorazione, abbiamo ancora poche inofrmazioni utili per la previsione dell'andamento del settore. Studiamo dunque l'evoluzione del settore ristorazione con somministrazione per le attivazioni nel dettaglio:
attFrames[1].sum()
CONTRATTO 424929 CONTR_N 424929 SETTORE 424929 SETT_ID 424929 STATO 424929 ETA 424929 GENERE 424929 DATE 424929 MESE 424929 ANNO 424929 PIL MLN EUR ANNUO 424929 dtype: int64
#raggruppo per giorno le attivazioni del settore ristorazione
ristorazioneDaily = dfOrdAtt.loc[dfOrdAtt['SETTORE'] == 'Ristorazione con somministrazione']
ristorazioneDaily = ristorazioneDaily.resample('D').count().iloc[:, [2]]
ristorazioneDaily.rename(columns={'SETTORE': 'VALUES'}, inplace=True)
ristorazioneDaily.plot()
<AxesSubplot:xlabel='DATA'>
resultsDict = {}
predictionsDict = {}
split_date = '2020-08-30'
df_training = ristorazioneDaily.loc[ristorazioneDaily.index <= split_date]
df_test = ristorazioneDaily.loc[ristorazioneDaily.index > split_date]
print(f"{len(df_training)} days of training data \n {len(df_test)} days of testing data ")
3894 days of training data 466 days of testing data
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Single esponential smoothing (SES)
Il metodo Simple Exponential Smoothing (SES) modella il passo temporale successivo come una funzione lineare ponderata esponenzialmente sulle osservazioni dei passi temporali precedenti. Questo metodo prevede che le nostre serie temporali siano stazionarie per poter funzionare in modo adeguato (nessun trend o stagionalità).
# Walk throught the test data, training and predicting 1 day ahead for all the test data
index = len(df_training)
yhat = list()
for t in tqdm(range(len(df_test.VALUES))):
temp_train = ristorazioneDaily[:len(df_training)+t]
model = SimpleExpSmoothing(temp_train.VALUES)
model_fit = model.fit()
predictions = model_fit.predict(start=len(temp_train), end=len(temp_train))
yhat = yhat + [predictions]
yhat = pd.concat(yhat)
resultsDict['SES'] = evaluate(df_test.VALUES, yhat.values)
predictionsDict['SES'] = yhat.values
100%|██████████| 466/466 [00:12<00:00, 37.04it/s]
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Holt Winter’s Exponential Smoothing (HWES)
Il metodo Simple Exponential Smoothing (SES) è derivato dal single esponential smoothing ma tiene conto della componente stagionale della serie e del trend
# Walk throught the test data, training and predicting 1 day ahead for all the test data
index = len(df_training)
yhat = list()
for t in tqdm(range(len(df_test.VALUES))):
temp_train = ristorazioneDaily[:len(df_training)+t]
model = ExponentialSmoothing(temp_train.VALUES)
model_fit = model.fit()
predictions = model_fit.predict(start=len(temp_train), end=len(temp_train))
yhat = yhat + [predictions]
yhat = pd.concat(yhat)
resultsDict['HWES'] = evaluate(df_test.VALUES, yhat.values)
predictionsDict['HWES'] = yhat.values
100%|██████████| 466/466 [00:12<00:00, 36.15it/s]
ARIMA
Autoregressive integrated moving average (ARIMA)
In un modello ARIMA ci sono 3 parametri che vengono utilizzati per modellare gli aspetti principali di una serie temporale: stagionalità, tendenza e rumore. Questi parametri sono contrassegnati dalle lettere p, d e q.
Numero di termini AR (autoregressivi) (p): p è il parametro associato all'aspetto autoregressivo del modello, che incorpora i valori passati, ossia i lag della variabile dipendente. Ad esempio, se p è 5, i predittori per x(t) saranno x(t-1)....x(t-5).
Numero di differenze (d): d è il parametro associato alla parte integrata del modello, che influisce sulla quantità di differenze da applicare a una serie temporale.
Numero di termini MA (Moving Average) (q): q è la dimensione della finestra della parte media mobile del modello, ovvero degli errori di previsione ritardati nell'equazione di previsione. Ad esempio, se q è 5, i predittori per x(t) saranno e(t-1)....e(t-5) dove e(i) è la differenza tra la media mobile all'iesimo istante e il valore effettivo.
Regolazione dei parametri ARIMA
Le serie non stazionarie richiedono un livello di differenziazione (d) >0 in ARIMA Selezionare i valori di ritardo per i parametri di autoregressione (AR) e di media mobile (MA), rispettivamente p e q, utilizzando i tracciati PACF, ACF e AUTOARIMA.
Nota: un problema dell'ARIMA è che non supporta i dati stagionali. Cioè una serie temporale con un ciclo che si ripete. L'ARIMA si aspetta che i dati non siano stagionali o che la componente stagionale sia stata rimossa, ad esempio destagionalizzata con metodi quali la differenziazione stagionale.
# ARIMA example
# Walk throught the test data, training and predicting 1 day ahead for all the test data
index = len(df_training)
yhat = list()
for t in tqdm(range(len(df_test.VALUES))):
temp_train = ristorazioneDaily[:len(df_training)+t]
model = ARIMA(temp_train.VALUES, order=(1, 0, 0))
model_fit = model.fit()
predictions = model_fit.predict(
start=len(temp_train), end=len(temp_train), dynamic=False)
yhat = yhat + [predictions]
yhat = pd.concat(yhat)
resultsDict['ARIMA'] = evaluate(df_test.VALUES, yhat.values)
predictionsDict['ARIMA'] = yhat.values
100%|██████████| 466/466 [02:24<00:00, 3.23it/s]
plt.plot(df_test.VALUES.values, label='Original')
plt.plot(yhat.values, color='red', label='ARIMA predicted')
plt.legend()
<matplotlib.legend.Legend at 0x229f7292190>
AUTO ARIMA
autoModel = pm.auto_arima(df_training.VALUES, trace=True,
error_action='ignore', suppress_warnings=True, seasonal=False)
autoModel.fit(df_training.VALUES)
Performing stepwise search to minimize aic ARIMA(2,1,2)(0,0,0)[0] intercept : AIC=50357.270, Time=1.99 sec ARIMA(0,1,0)(0,0,0)[0] intercept : AIC=51832.790, Time=0.16 sec ARIMA(1,1,0)(0,0,0)[0] intercept : AIC=51038.821, Time=0.49 sec ARIMA(0,1,1)(0,0,0)[0] intercept : AIC=50536.689, Time=1.53 sec ARIMA(0,1,0)(0,0,0)[0] : AIC=51830.790, Time=0.10 sec ARIMA(1,1,2)(0,0,0)[0] intercept : AIC=50462.312, Time=1.60 sec ARIMA(2,1,1)(0,0,0)[0] intercept : AIC=50416.693, Time=1.14 sec ARIMA(3,1,2)(0,0,0)[0] intercept : AIC=50357.102, Time=3.77 sec ARIMA(3,1,1)(0,0,0)[0] intercept : AIC=inf, Time=6.98 sec ARIMA(4,1,2)(0,0,0)[0] intercept : AIC=50344.113, Time=4.48 sec ARIMA(4,1,1)(0,0,0)[0] intercept : AIC=50346.996, Time=3.79 sec ARIMA(5,1,2)(0,0,0)[0] intercept : AIC=50346.064, Time=9.60 sec ARIMA(4,1,3)(0,0,0)[0] intercept : AIC=50346.013, Time=6.42 sec ARIMA(3,1,3)(0,0,0)[0] intercept : AIC=50353.639, Time=6.93 sec ARIMA(5,1,1)(0,0,0)[0] intercept : AIC=50348.158, Time=4.17 sec ARIMA(5,1,3)(0,0,0)[0] intercept : AIC=inf, Time=13.01 sec ARIMA(4,1,2)(0,0,0)[0] : AIC=50342.115, Time=2.39 sec ARIMA(3,1,2)(0,0,0)[0] : AIC=50355.105, Time=1.74 sec ARIMA(4,1,1)(0,0,0)[0] : AIC=50344.999, Time=1.89 sec ARIMA(5,1,2)(0,0,0)[0] : AIC=50344.065, Time=7.81 sec ARIMA(4,1,3)(0,0,0)[0] : AIC=50344.014, Time=4.17 sec ARIMA(3,1,1)(0,0,0)[0] : AIC=inf, Time=6.43 sec ARIMA(3,1,3)(0,0,0)[0] : AIC=50351.642, Time=3.05 sec ARIMA(5,1,1)(0,0,0)[0] : AIC=50346.161, Time=2.16 sec ARIMA(5,1,3)(0,0,0)[0] : AIC=inf, Time=8.43 sec Best model: ARIMA(4,1,2)(0,0,0)[0] Total fit time: 104.299 seconds
ARIMA(order=(4, 1, 2), scoring_args={}, suppress_warnings=True,
with_intercept=False)
order = autoModel.order
yhat = list()
for t in tqdm(range(len(df_test.VALUES))):
temp_train = ristorazioneDaily[:len(df_training)+t]
model = ARIMA(temp_train.VALUES, order=order)
model_fit = model.fit()
predictions = model_fit.predict(
start=len(temp_train), end=len(temp_train), dynamic=False)
yhat = yhat + [predictions]
yhat = pd.concat(yhat)
resultsDict['AutoARIMA {0}'.format(order)] = evaluate(
df_test.VALUES, yhat)
predictionsDict['AutoARIMA {0}'.format(order)] = yhat.values
100%|██████████| 466/466 [18:47<00:00, 2.42s/it]
plt.plot(df_test.VALUES.values, label='Original')
plt.plot(yhat.values, color='red', label='AutoARIMA {0}'.format(order))
plt.legend()
<matplotlib.legend.Legend at 0x22c47b6a490>
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Seasonal Autoregressive Integrated Moving-Average (SARIMA)
Seasonal Autoregressive Integrated Moving Average, SARIMA o ARIMA stagionale, è un'estensione di ARIMA che supporta esplicitamente dati di serie temporali univariate con una componente stagionale.
Aggiunge tre nuovi iperparametri per specificare l'autoregressione (AR), la differenziazione (I) e la media mobile (MA) per la componente stagionale della serie, oltre a un parametro aggiuntivo per il periodo della stagionalità.
Elementi di tendenza:
Sono tre gli elementi di trend che richiedono una configurazione. Sono gli stessi del modello ARIMA, in particolare:
p: Ordine di autoregressione del trend.
d: Ordine di differenza del trend.
q: ordine della media mobile del trend.
Elementi stagionali:
Sono quattro gli elementi stagionali che non fanno parte dell'ARIMA e che devono essere configurati:
P: ordine autoregressivo stagionale.
D: Ordine di differenza stagionale.
Q: ordine di media mobile stagionale.
m: Il numero di passi temporali per un singolo periodo stagionale. Ad esempio, una S di 12 per i dati mensili suggerisce un ciclo stagionale annuale.
Notazione SARIMA: SARIMA(p,d,q)(P,D,Q,m)
# SARIMA example
# Walk throught the test data, training and predicting 1 day ahead for all the test data
index = len(df_training)
yhat = list()
for t in tqdm(range(len(df_test.VALUES))):
temp_train = ristorazioneDaily[:len(df_training)+t]
model = SARIMAX(temp_train.VALUES, order=(
1, 0, 0), seasonal_order=(0, 0, 0, 3))
model_fit = model.fit(disp=False)
predictions = model_fit.predict(
start=len(temp_train), end=len(temp_train), dynamic=False)
yhat = yhat + [predictions]
yhat = pd.concat(yhat)
resultsDict['SARIMAX'] = evaluate(df_test.VALUES, yhat.values)
predictionsDict['SARIMAX'] = yhat.values
100%|██████████| 466/466 [00:56<00:00, 8.18it/s]
plt.plot(df_test.VALUES.values, label='Original')
plt.plot(yhat.values, color='red', label='SARIMAX')
plt.legend()
<matplotlib.legend.Legend at 0x229f721d700>
Prophet è un modello rilasciato da Facebook. Si tratta essenzialmente di un approccio di curve fitting,
ma utilizza modelli additivi generalizzati invece di una rappresentazione dello spazio degli stati per descrivere ogni componente.
# Prophet needs some specifics data stuff, coment it here
prophet_training = df_training.rename(
columns={'VALUES': 'y'}) # old method
prophet_training['ds'] = prophet_training.index
prophet_training.index = pd.RangeIndex(len(prophet_training.index))
prophet_test = df_test.rename(columns={'VALUES': 'y'}) # old method
prophet_test['ds'] = prophet_test.index
prophet_test.index = pd.RangeIndex(len(prophet_test.index))
prophet = Prophet(
growth='linear',
seasonality_mode='multiplicative',
holidays_prior_scale=20,
weekly_seasonality=False,
daily_seasonality= True,
yearly_seasonality=False
).add_seasonality(
name='monthly',
period=30.5,
fourier_order=55
).add_seasonality(
name='daily',
period=1,
fourier_order=15
).add_seasonality(
name='weekly',
period=7,
fourier_order=25
).add_seasonality(
name='yearly',
period=365.25,
fourier_order=20
).add_seasonality(
name='quarterly',
period=365.25/4,
fourier_order=55
).add_country_holidays(country_name='Italy')
prophet.fit(prophet_training)
yhat = prophet.predict(prophet_test)
resultsDict['Prophet univariate'] = evaluate(
df_test.VALUES, yhat.yhat.values)
predictionsDict['Prophet univariate'] = yhat.yhat.values
c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\prophet\forecaster.py:896: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. components = components.append(new_comp) c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\prophet\forecaster.py:896: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. components = components.append(new_comp) c:\Users\ggudy\anaconda3\envs\ProgettoUni\lib\site-packages\prophet\forecaster.py:896: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. components = components.append(new_comp)
plt.plot(df_test.VALUES.values, label='Original')
plt.plot(yhat.yhat, color='red', label='Prophet univariate')
plt.legend()
<matplotlib.legend.Legend at 0x22c810a8fa0>
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Costruzione di un dataset multivariato per la time series
# ADD time features to our model
def create_time_features(df, target=None):
"""
Creates time series features from datetime index
"""
df['date'] = df.index
df['quarter'] = df['date'].dt.quarter
df['month'] = df['date'].dt.month
df['year'] = df['date'].dt.year
df['dayofyear'] = df['date'].dt.dayofyear
df['dayofmonth'] = df['date'].dt.day
df['weekofyear'] = df['date'].dt.weekofyear
X = df.drop(['date'], axis=1)
if target:
y = df[target]
X = X.drop([target], axis=1)
return X, y
return X
X_train_df, y_train = create_time_features(
df_training, target='VALUES')
X_test_df, y_test = create_time_features(df_test, target='VALUES')
scaler = StandardScaler()
scaler.fit(X_train_df) # No cheating, never scale on the training+test!
X_train = scaler.transform(X_train_df)
X_test = scaler.transform(X_test_df)
X_train_df = pd.DataFrame(X_train, columns=X_train_df.columns)
X_test_df = pd.DataFrame(X_test, columns=X_test_df.columns)
C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:6: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['date'] = df.index C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:7: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['quarter'] = df['date'].dt.quarter C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:8: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['month'] = df['date'].dt.month C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['year'] = df['date'].dt.year C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:10: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['dayofyear'] = df['date'].dt.dayofyear C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:11: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['dayofmonth'] = df['date'].dt.day C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:12: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated. Please use Series.dt.isocalendar().week instead. df['weekofyear'] = df['date'].dt.weekofyear C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:12: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['weekofyear'] = df['date'].dt.weekofyear C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:6: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['date'] = df.index C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:7: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['quarter'] = df['date'].dt.quarter C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:8: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['month'] = df['date'].dt.month C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:9: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['year'] = df['date'].dt.year C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:10: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['dayofyear'] = df['date'].dt.dayofyear C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:11: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['dayofmonth'] = df['date'].dt.day C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:12: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated. Please use Series.dt.isocalendar().week instead. df['weekofyear'] = df['date'].dt.weekofyear C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\2000014208.py:12: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df['weekofyear'] = df['date'].dt.weekofyear
MODELLI AD ALBERO
RANDOM FOREST
Il random forest è un metodo di apprendimento collettivo per la classificazione o la regressione che opera costruendo una moltitudine di alberi decisionali al momento dell'addestramento. Per i compiti di classificazione, l'output del rando forest è la classe selezionata dalla maggior parte degli alberi. Per i compiti di regressione, viene restituita la previsione media dei singoli alberi. Molto utile perchè gli alberi decisionali non trasmettono l'errore relativo nella valutazione
reg = RandomForestRegressor(max_depth=2, random_state=0)
reg.fit(X_train, y_train)
yhat = reg.predict(X_test)
resultsDict['Randomforest'] = evaluate(df_test.VALUES, yhat)
predictionsDict['Randomforest'] = yhat
XGBOOST
Metodo di regressione che utilizza gli alberi di valutazione come il random forest, ma implementando una componente di boosting.
Il boosting è un metodo d'insieme, ovvero un modo per combinare le previsioni di diversi modelli in uno solo.
Lo fa prendendo ogni predittore in sequenza e modellandolo in base all'errore del suo predecessore (dando più peso ai predittori che hanno prestazioni migliori):
1.Adatta un primo modello utilizzando i dati originali
2.Adatta un secondo modello utilizzando i residui del primo modello.
3.Crea un terzo modello utilizzando la somma dei modelli 1 e 2.
Il Gradient Boosting è un tipo specifico di boosting, chiamato così perché minimizza la funzione di perdita utilizzando un algoritmo di gradient descent.
reg = xgb.XGBRegressor(objective='reg:squarederror', n_estimators=2000)
reg.fit(X_train, y_train,
verbose=False) # Change verbose to True if you want to see it train
yhat = reg.predict(X_test)
resultsDict['XGBoost'] = evaluate(df_test.VALUES, yhat)
predictionsDict['XGBoost'] = yhat
plt.plot(df_test.VALUES.values, label='Original')
plt.plot(yhat, color='red', label='XGboost')
plt.legend()
<matplotlib.legend.Legend at 0x22c8d7f57c0>
models = ['Randomforest',
'SARIMAX',
'XGBoost',
'ARIMA',
'Prophet univariate',
'HWES',
'SES']
resis = pd.DataFrame(data={k: df_test.VALUES.values -
v for k, v in predictionsDict.items()})[models]
corr3 = resis.corr()
print("Residuals correlation")
Residuals correlation
sns.set_theme (style = 'white')
heatmap = sns.heatmap(corr3, annot = True)
plt.title('Relation of forecasting models') #describing relation between regression models we have tested
Text(0.5, 1.0, 'Relation of forecasting models')
resultsDict
{'SES': {'mae': 96.63231902621622,
'rmse': 181.61570856841328,
'mape': 262837716843.26187,
'r2': 0.05028103465938616},
'HWES': {'mae': 96.65029708418136,
'rmse': 181.62303758070954,
'mape': 262955940372.913,
'r2': 0.0502043822324173},
'ARIMA': {'mae': 112.50078797276525,
'rmse': 174.8924784302066,
'mape': 418056127030.0826,
'r2': 0.11929480860425312},
'AutoARIMA (4, 1, 2)': {'mae': 94.4297179004374,
'rmse': 183.04710827623651,
'mape': 250023568505.88513,
'r2': 0.035251667352522276},
'SARIMAX': {'mae': 81.4611214210943,
'rmse': 181.9541931129425,
'mape': 61003638790.76521,
'r2': 0.046737676457691446},
'Prophet univariate': {'mae': 84.195219821467,
'rmse': 161.14071836240905,
'mape': 164677208097.10394,
'r2': 0.25234906183548866},
'Randomforest': {'mae': 101.9406476255874,
'rmse': 177.10481520958274,
'mape': 221009006416.1009,
'r2': 0.09687257589353537},
'XGBoost': {'mae': 99.12256252858563,
'rmse': 194.3084426753558,
'mape': 148356478580.61917,
'r2': -0.08710535217312043}}
STUDIO DEL SETTORE RELATIVO ALLA RISTORAZIONE E CONSIDERAZIONI SUI RISULTATI DI DIFFERENTI MODELLI DI FORECASTING:
Studio con approccio relativo a time series mensile e auto sarima
attFrames[1]
attTimeSeRist = attFrames[1].iloc[:, [2]]
attTimeSeRist.rename(columns={'SETTORE': 'N.ATTIVATI'}, inplace=True)
attTimeSeRist
| N.ATTIVATI | |
|---|---|
| DATA | |
| 2010-01-31 | 2254 |
| 2010-02-28 | 2139 |
| 2010-03-31 | 1869 |
| 2010-04-30 | 1867 |
| 2010-05-31 | 2054 |
| ... | ... |
| 2021-08-31 | 2016 |
| 2021-09-30 | 2401 |
| 2021-10-31 | 2467 |
| 2021-11-30 | 2042 |
| 2021-12-31 | 1796 |
144 rows × 1 columns
attTimeSeRist.plot()
<AxesSubplot:xlabel='DATA'>
plot_acf(attTimeSeRist)
analysis = attTimeSeRist['N.ATTIVATI'].copy()
decompose_result_mult = seasonal_decompose(analysis, model="multiplicative")
trend = decompose_result_mult.trend
seasonal = decompose_result_mult.seasonal
residual = decompose_result_mult.resid
decompose_result_mult.plot();
cwd = os.getcwd()
path = cwd + '/Ristorazione'
analysis.to_csv(path)
toStation = analysis.diff().dropna()
plt.figure(figsize=(12,5))
ax1 = toStation.plot()
ax1.set_xlabel("Date")
ax1.set_ylabel("Count")
plt.grid(True)
plt.show()
test_result=adfuller(attTimeSeRist['N.ATTIVATI'])
adfuller_test(attTimeSeRist['N.ATTIVATI'])
ADF Test Statistic : -2.100352518908367 p-value : 0.24437287550497844 #Lags Used : 2 Number of Observations : 141
attTimeSeRist['Difference'] = attTimeSeRist['N.ATTIVATI'] - attTimeSeRist['N.ATTIVATI'].shift(1)
attTimeSeRist['Seasonal First Difference']=attTimeSeRist['N.ATTIVATI']-attTimeSeRist['N.ATTIVATI'].shift(12)
attTimeSeRist.head()
C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\1124636589.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy attTimeSeRist['Difference'] = attTimeSeRist['N.ATTIVATI'] - attTimeSeRist['N.ATTIVATI'].shift(1) C:\Users\ggudy\AppData\Local\Temp\ipykernel_6396\1124636589.py:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy attTimeSeRist['Seasonal First Difference']=attTimeSeRist['N.ATTIVATI']-attTimeSeRist['N.ATTIVATI'].shift(12)
| N.ATTIVATI | Difference | Seasonal First Difference | |
|---|---|---|---|
| DATA | |||
| 2010-01-31 | 2254 | NaN | NaN |
| 2010-02-28 | 2139 | -115.0 | NaN |
| 2010-03-31 | 1869 | -270.0 | NaN |
| 2010-04-30 | 1867 | -2.0 | NaN |
| 2010-05-31 | 2054 | 187.0 | NaN |
adfuller_test(attTimeSeRist ['Seasonal First Difference'].dropna())
ADF Test Statistic : -1.3957124047674545 p-value : 0.5843299106614225 #Lags Used : 13 Number of Observations : 118
tfram4 = attTimeSeRist['N.ATTIVATI']
stepwise_model3 = auto_arima(tfram4, start_p=1, start_q=1,
max_p=3, max_q=3, m=12,
start_P=0, seasonal=True,
d=1, D=1, trace=True,
error_action='ignore',
suppress_warnings=True,
stepwise=True)
print(stepwise_model3.aic())
Performing stepwise search to minimize aic ARIMA(1,1,1)(0,1,1)[12] : AIC=inf, Time=1.10 sec ARIMA(0,1,0)(0,1,0)[12] : AIC=2189.130, Time=0.04 sec ARIMA(1,1,0)(1,1,0)[12] : AIC=2146.605, Time=0.83 sec ARIMA(0,1,1)(0,1,1)[12] : AIC=inf, Time=0.78 sec ARIMA(1,1,0)(0,1,0)[12] : AIC=2175.748, Time=0.04 sec ARIMA(1,1,0)(2,1,0)[12] : AIC=2127.035, Time=1.06 sec ARIMA(1,1,0)(2,1,1)[12] : AIC=inf, Time=3.60 sec ARIMA(1,1,0)(1,1,1)[12] : AIC=inf, Time=1.16 sec ARIMA(0,1,0)(2,1,0)[12] : AIC=2140.926, Time=1.23 sec ARIMA(2,1,0)(2,1,0)[12] : AIC=2107.443, Time=2.52 sec ARIMA(2,1,0)(1,1,0)[12] : AIC=2116.324, Time=0.61 sec ARIMA(2,1,0)(2,1,1)[12] : AIC=inf, Time=2.54 sec ARIMA(2,1,0)(1,1,1)[12] : AIC=inf, Time=1.32 sec ARIMA(3,1,0)(2,1,0)[12] : AIC=2106.696, Time=1.64 sec ARIMA(3,1,0)(1,1,0)[12] : AIC=2113.197, Time=0.75 sec ARIMA(3,1,0)(2,1,1)[12] : AIC=inf, Time=3.45 sec ARIMA(3,1,0)(1,1,1)[12] : AIC=inf, Time=0.83 sec ARIMA(3,1,1)(2,1,0)[12] : AIC=2105.743, Time=2.93 sec ARIMA(3,1,1)(1,1,0)[12] : AIC=2113.177, Time=0.93 sec ARIMA(3,1,1)(2,1,1)[12] : AIC=inf, Time=4.26 sec ARIMA(3,1,1)(1,1,1)[12] : AIC=inf, Time=1.86 sec ARIMA(2,1,1)(2,1,0)[12] : AIC=2107.364, Time=1.84 sec ARIMA(3,1,2)(2,1,0)[12] : AIC=2107.604, Time=3.46 sec ARIMA(2,1,2)(2,1,0)[12] : AIC=2109.219, Time=2.46 sec ARIMA(3,1,1)(2,1,0)[12] intercept : AIC=2107.573, Time=5.43 sec Best model: ARIMA(3,1,1)(2,1,0)[12] Total fit time: 46.713 seconds 2105.7425602756894
fig = stepwise_model3.plot_diagnostics()
fig.set_size_inches(18.5, 10.5, forward=True)
plt.show()
# Train Test Split Index
train_size = 0.9
split_idx = round(len(tfram4)* train_size)
split_idx
# Split
train3 = tfram4.iloc[:split_idx]
test3 = tfram4.iloc[split_idx:]
# Visualize split
fig,ax= plt.subplots(figsize=(12,8))
kws = dict(marker='o')
plt.plot(train3, label='Train', **kws)
plt.plot(test3, label='Test', **kws)
ax.legend(bbox_to_anchor=[1,1]);
stepwise_model3.fit(train3)
ARIMA(order=(3, 1, 1), scoring_args={}, seasonal_order=(2, 1, 0, 12),
suppress_warnings=True, with_intercept=False)
future2, cf3 = stepwise_model3.predict(n_periods=14, return_conf_int=True)
future2 = pd.DataFrame(future2,index = test3.index, columns=['Prediction'])
cc = pd.concat([test3,future2],axis=1)
cc.plot(**kwsnep, figsize=(20, 10))
<AxesSubplot:xlabel='DATA'>
index_of2 = pd.date_range(tfram4.index[-1], periods = 14, freq='MS')
f = future2
f = f.set_index(index_of2)
# Plot Della prediction
plt.figure(figsize=(25, 15))
plt.plot(tfram4, color='blue', label='Actual Date', **kwsn)
plt.plot(f, color='red', label='Predict', **kwsn)
plt.legend(loc='lower right', fontsize=15)
plt.title("Predizione cessati")
plt.show()
mape = mean_absolute_percentage_error(test3, f.Prediction)
print(mape)
0.3430122514976612
MSE = mean_squared_error(test3, f)
RMSE = math.sqrt(MSE)
print('The mean square error is: ', MSE)
print('The Root Mean Square error is: ', RMSE)
The mean square error is: 1002977.8325520398 The Root Mean Square error is: 1001.4878094874844